@openhands/agent-canvas 1.0.0-rc.1 → 1.0.0-rc.3

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 (460) hide show
  1. package/README.md +2 -2
  2. package/README.windows.md +2 -2
  3. package/build/assets/{QueryClientProvider-w1cZWY41.js → QueryClientProvider-7oLZ1RtQ.js} +1 -1
  4. package/build/assets/{Trans-BJeYqz2A.js → Trans-rF21Jwln.js} +1 -1
  5. package/build/assets/acp-providers-C55k29rf.js +1 -0
  6. package/build/assets/active-backend-context-CQTk4wD8.js +1 -0
  7. package/build/assets/add-backend-modal-BdYxoUdL.js +1 -0
  8. package/build/assets/agent-server-client-options-Dvgeb3x4.js +1 -0
  9. package/build/assets/agent-server-compatibility-BANjmMTo.js +1 -0
  10. package/build/assets/agent-server-conversation-service.api-js3oYcdU.js +5 -0
  11. package/build/assets/{agent-settings-BXBaybB_.js → agent-settings-BNrffu3I.js} +1 -1
  12. package/build/assets/{alert-banner-NeUl1-PQ.js → alert-banner-BzU93oDh.js} +1 -1
  13. package/build/assets/{analytics-consent-form-modal-DxkThW4K.js → analytics-consent-form-modal-Ce-_Skcd.js} +1 -1
  14. package/build/assets/api-key-entry-screen-CGyS-Cna.js +1 -0
  15. package/build/assets/{app-settings-C-U6jONZ.js → app-settings-DmOs4oik.js} +1 -1
  16. package/build/assets/automation-detail-DLbCVJCw.js +1 -0
  17. package/build/assets/{automations-list-BLJzAd-p.js → automations-list-Ces5shz5.js} +1 -1
  18. package/build/assets/{back-nav-button-DgkK0Ka6.js → back-nav-button-BDM9vr_o.js} +1 -1
  19. package/build/assets/backend-form-modal-BUy-PzZN.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-BktJcGgH.js → backend-synced-settings-badge-1A63yxGs.js} +1 -1
  21. package/build/assets/{base-modal-DZCNv0A4.js → base-modal-Ba5WcNb6.js} +1 -1
  22. package/build/assets/{brand-button-LBFNic99.js → brand-button-BoiPxAGm.js} +1 -1
  23. package/build/assets/browser-B8bp1IqT.js +5 -0
  24. package/build/assets/browser-store-C5uQbbIi.js +1 -0
  25. package/build/assets/{browser-tab-be3QvXg9.js → browser-tab-CiBRWB4X.js} +1 -1
  26. package/build/assets/chat-send-button-qKFZuB9E.js +1 -0
  27. package/build/assets/check-BDAbW7je.js +1 -0
  28. package/build/assets/{checkmark-Rmpruj7q.js → checkmark-SEZPnU2I.js} +1 -1
  29. package/build/assets/{chevron-down-KhWYEjeW.js → chevron-down-DUxWwzTm.js} +1 -1
  30. package/build/assets/{chevron-left-small-6nyFCWVQ.js → chevron-left-small-x9_-ucHG.js} +1 -1
  31. package/build/assets/{circle-plus-check-toggle-DquBwJ_6.js → circle-plus-check-toggle-CboDp7XB.js} +1 -1
  32. package/build/assets/{close-D_o3d8QM.js → close-CbOsKMRg.js} +1 -1
  33. package/build/assets/{code-tag-DhsjDB-v.js → code-tag-C0vR_IQH.js} +1 -1
  34. package/build/assets/{color-themes-0biOprdo.js → color-themes-B9n7pBQl.js} +1 -1
  35. package/build/assets/{combobox-caret-CO7eozIY.js → combobox-caret-DwMmhrrA.js} +1 -1
  36. package/build/assets/{command-store-UzKGSUC2.js → command-store-BUWgE-vZ.js} +1 -1
  37. package/build/assets/{condenser-settings-BulzYEuW.js → condenser-settings-FCBjvqSo.js} +1 -1
  38. package/build/assets/{confirmation-modal-CMAtd9R0.js → confirmation-modal-BPgWqWRI.js} +1 -1
  39. package/build/assets/{context-menu-list-item-D0swnhFt.js → context-menu-list-item-CHWCx1Mc.js} +1 -1
  40. package/build/assets/conversation-CT8AvxEH.js +1 -0
  41. package/build/assets/conversation-panel-DqDDs4WZ.js +1 -0
  42. package/build/assets/conversation-service.api-y_eB_43m.js +1 -0
  43. package/build/assets/conversation-state-store-DpgQaK_O.js +1 -0
  44. package/build/assets/conversation-store-CiYGBud3.js +6 -0
  45. package/build/assets/{conversation-tab-empty-state-DYjKsg_c.js → conversation-tab-empty-state-Ba5hbJhn.js} +1 -1
  46. package/build/assets/conversation-vNuLKgz6.js +19 -0
  47. package/build/assets/conversation-websocket-context-Bb4XBXoc.js +3 -0
  48. package/build/assets/{copy-BM0RpLez.js → copy-CAxUvM-U.js} +1 -1
  49. package/build/assets/{custom-toast-handlers-BohXx7uh.js → custom-toast-handlers-fgD4IYsu.js} +1 -1
  50. package/build/assets/{declaration-DaUdB2Wg.js → declaration-IA661TBv.js} +1 -1
  51. package/build/assets/{device-verify-DiEJqpJb.js → device-verify-BOQz2LJQ.js} +1 -1
  52. package/build/assets/{dist-xtCm0O6P.js → dist-B-SKiGDl.js} +1 -1
  53. package/build/assets/dist-CeJSjcAI.js +1 -0
  54. package/build/assets/{dropdown-classes-Vqz86I0R.js → dropdown-classes-lT1LUsbO.js} +1 -1
  55. package/build/assets/edit-automation-modal-C-oC5tis.js +1 -0
  56. package/build/assets/ellipsis-button-CiLx8dqc.js +1 -0
  57. package/build/assets/{entry.client-BvKgdCQ9.js → entry.client-Db3BpFL_.js} +2 -2
  58. package/build/assets/{enum-filter-dropdown-DdFgk0EM.js → enum-filter-dropdown-DFwoVtOw.js} +1 -1
  59. package/build/assets/{environment-switch-overlay-CuBuZOaa.js → environment-switch-overlay-Cow6h62p.js} +1 -1
  60. package/build/assets/{extensions-hub-Dayqvv0n.js → extensions-hub-BxZbAtjP.js} +1 -1
  61. package/build/assets/extensions-navigation-BIb-vAa2.js +1 -0
  62. package/build/assets/{file-DwHCkWZT.js → file-BJCSojij.js} +1 -1
  63. package/build/assets/files-tab-DpulQlIo.js +1 -0
  64. package/build/assets/files-tab-store-CZAEwv3x.js +1 -0
  65. package/build/assets/{folder-2h1hR1Qb.js → folder-wShAU0y7.js} +1 -1
  66. package/build/assets/git-control-bar-branch-button-D1uam-nI.js +27 -0
  67. package/build/assets/{globe-qFjFNG6J.js → globe-CQ_5xwpo.js} +1 -1
  68. package/build/assets/home-sJAFzI6v.js +1 -0
  69. package/build/assets/{i18n-zDndR1Ne.js → i18n-CyvU1o95.js} +1 -1
  70. package/build/assets/install-server-modal-BjEzlLF5.js +1 -0
  71. package/build/assets/{launch-I00QV8YT.js → launch-DgtB1JTX.js} +1 -1
  72. package/build/assets/{lesson-plan-C18uB_56.js → lesson-plan-B607buca.js} +1 -1
  73. package/build/assets/{link-external-DtcdPFbw.js → link-external-DCsHkAj4.js} +1 -1
  74. package/build/assets/llm-client-BnqeDPua.js +1 -0
  75. package/build/assets/llm-settings-B8kPJ0Of.js +1 -0
  76. package/build/assets/llm-settings-CjUpPsvA.js +1 -0
  77. package/build/assets/{loading-spinner-DNwR4--Z.js → loading-spinner-CFuA0UNt.js} +1 -1
  78. package/build/assets/manage-backends-modal-CTA-2x4F.js +1 -0
  79. package/build/assets/manifest-d3e8504d.js +1 -0
  80. package/build/assets/{markdown-renderer-D6B-u2nM.js → markdown-renderer-oOUs3tw5.js} +1 -1
  81. package/build/assets/mcp-client-xEdbDxOL.js +1 -0
  82. package/build/assets/mcp-kJYdM8aJ.js +9 -0
  83. package/build/assets/messages-BFJXB6MW.js +36 -0
  84. package/build/assets/{modal-backdrop-BDqI1zBV.js → modal-backdrop-B1si6TUd.js} +1 -1
  85. package/build/assets/{modal-body-CCLCqX1J.js → modal-body-2Po2nl1e.js} +1 -1
  86. package/build/assets/{modal-classes-DwTdT3IK.js → modal-classes-9XTtWCtF.js} +1 -1
  87. package/build/assets/{modal-close-button-gQgKqUf-.js → modal-close-button-DY-rVmld.js} +1 -1
  88. package/build/assets/model-selector-z_QOzaRV.js +1 -0
  89. package/build/assets/{navigation-context-aNGUUtdq.js → navigation-context-CszaA-CJ.js} +1 -1
  90. package/build/assets/{navigation-link-CYkF2y3K.js → navigation-link-DXg4oo29.js} +1 -1
  91. package/build/assets/onboarding-CZ_7nd-M.js +1 -0
  92. package/build/assets/{openhands-logo-CHmtDV-t.js → openhands-logo-B-IDE1ER.js} +1 -1
  93. package/build/assets/{option-service.api-CGNANEcT.js → option-service.api-DHOGfYKh.js} +1 -1
  94. package/build/assets/organization-service.api-D79cdERN.js +1 -0
  95. package/build/assets/path-utils-0KWEiRs9.js +1 -0
  96. package/build/assets/{pencil-Dr0b2jL1.js → pencil-COslZGUC.js} +1 -1
  97. package/build/assets/{plan-components--aLlpASH.js → plan-components-DsiDjcDi.js} +1 -1
  98. package/build/assets/{planner-tab-B-5EeCEm.js → planner-tab-CNmJiZ22.js} +1 -1
  99. package/build/assets/plus-D8aJZRkD.js +1 -0
  100. package/build/assets/profiles-client-CesbAK-7.js +1 -0
  101. package/build/assets/{providers-DknP6O2g.js → providers-Bpq3xFRA.js} +1 -1
  102. package/build/assets/proxy-wIasY2Po.js +1 -0
  103. package/build/assets/{query-client-config-CWWGQWvw.js → query-client-config-CITeuHD7.js} +1 -1
  104. package/build/assets/{recommended-automations-launcher-BIul0osB.js → recommended-automations-launcher-B1kfmFTQ.js} +8 -10
  105. package/build/assets/root-CIZ7Rv1X.js +2 -0
  106. package/build/assets/root-layout-B5ijp9At.js +2 -0
  107. package/build/assets/{sdk-section-page-VmtJWH3A.js → sdk-section-page-DTyvCc52.js} +1 -1
  108. package/build/assets/{sdk-settings-schema-DFievvEK.js → sdk-settings-schema-B0KrqqPX.js} +1 -1
  109. package/build/assets/{search-BeVRXvX7.js → search-BqXT2Ied.js} +1 -1
  110. package/build/assets/secrets-service-rJqZtDmI.js +1 -0
  111. package/build/assets/{secrets-settings-BLMvCkKm.js → secrets-settings-BQNSDLKS.js} +1 -1
  112. package/build/assets/server-client-Cz8PyIbN.js +1 -0
  113. package/build/assets/settings-BUlJrO_h.js +1 -0
  114. package/build/assets/settings-client-BUlG0Gzq.js +1 -0
  115. package/build/assets/{settings-dropdown-input-DA_pzHWE.js → settings-dropdown-input-BUk4m23x.js} +1 -1
  116. package/build/assets/{settings-gear-aNebYlCy.js → settings-gear-DFmoMp-6.js} +1 -1
  117. package/build/assets/{settings-index-CycvkOoq.js → settings-index-DE91Eahc.js} +1 -1
  118. package/build/assets/{settings-input-8y5p4kze.js → settings-input-DsoZj8Dm.js} +1 -1
  119. package/build/assets/{settings-list-classes-Qk7zl0Wu.js → settings-list-classes-D8VAVZmi.js} +1 -1
  120. package/build/assets/{settings-modal-DdntdOGP.js → settings-modal-CCaPYVqW.js} +1 -1
  121. package/build/assets/{settings-section-header-context-B77tsYlx.js → settings-section-header-context-D61smD-W.js} +1 -1
  122. package/build/assets/settings-service.api-4u2RKC8k.js +1 -0
  123. package/build/assets/{settings-switch-ba4DuiNO.js → settings-switch-BQiAS9ga.js} +1 -1
  124. package/build/assets/{settings-utils-BxzHqLmZ.js → settings-utils-chxTa1vn.js} +1 -1
  125. package/build/assets/shared-conversation-sBPLAawM.js +1 -0
  126. package/build/assets/{sidebar-mobile-menu-toggle-C0mmabKj.js → sidebar-mobile-menu-toggle-BDXWzhyB.js} +1 -1
  127. package/build/assets/{sidebar-nav-link-BsYdDFfb.js → sidebar-nav-link-Bhlzlhp8.js} +1 -1
  128. package/build/assets/{skill-card-pill-row-BhUlGcYB.js → skill-card-pill-row-Bg5joQf6.js} +1 -1
  129. package/build/assets/{skills-TYjOUQ2d.js → skills-BDOWVle-.js} +1 -1
  130. package/build/assets/skills-client-Cr9F5306.js +1 -0
  131. package/build/assets/{skills-plugins-D0pdqgKa.js → skills-plugins-fihjo1KZ.js} +1 -1
  132. package/build/assets/{skills-settings-VqKTkmVl.js → skills-settings-NQnuMwZP.js} +1 -1
  133. package/build/assets/{styled-tooltip-TCp7svY3.js → styled-tooltip-GXy1qxsO.js} +1 -1
  134. package/build/assets/suspense-C9MBE_9N.js +1 -0
  135. package/build/assets/{switch-skeleton-cKrdaYGj.js → switch-skeleton-QpdcdxRP.js} +1 -1
  136. package/build/assets/{task-list-tab-BiizRsY3.js → task-list-tab-Hl9BuVfq.js} +1 -1
  137. package/build/assets/telemetry-j9SLrtY7.js +2 -0
  138. package/build/assets/{terminal-BSYITdM0.js → terminal-BUww3Ssl.js} +1 -1
  139. package/build/assets/{terminal-CpgZx6go.js → terminal-DRwe8--D.js} +1 -1
  140. package/build/assets/{toggle-switch-CUgOZqZu.js → toggle-switch-DDr-DnEc.js} +1 -1
  141. package/build/assets/{trash-2-CbVljPko.js → trash-2-DAKXV2Wm.js} +1 -1
  142. package/build/assets/{typography-Bvw0IxaN.js → typography-Cx7uw7z3.js} +1 -1
  143. package/build/assets/{u-check-circle-u9QiS4Fr.js → u-check-circle-CftRwky1.js} +1 -1
  144. package/build/assets/{u-check-circle-half-DjpjzWu3.js → u-check-circle-half-sGVk0BtL.js} +1 -1
  145. package/build/assets/{u-circuit-DlBlOwx9.js → u-circuit-Cg9tH5qb.js} +1 -1
  146. package/build/assets/{u-edit-BIYzjs3v.js → u-edit-foF02hwH.js} +1 -1
  147. package/build/assets/{use-active-conversation-q1wT8LI5.js → use-active-conversation-DJGoI9Mc.js} +1 -1
  148. package/build/assets/use-agent-settings-schema-DtusObuC.js +1 -0
  149. package/build/assets/{use-agent-state-CCHlVqvY.js → use-agent-state-BXgWhFh6.js} +1 -1
  150. package/build/assets/{use-cloud-current-user-id-BAKf91Zx.js → use-cloud-current-user-id-e1Pk7NxQ.js} +1 -1
  151. package/build/assets/use-config-DSzkljTq.js +1 -0
  152. package/build/assets/use-create-conversation-CzvaVA5A.js +1 -0
  153. package/build/assets/use-event-store-DSpvASbC.js +1 -0
  154. package/build/assets/use-get-secrets-DiLgP147.js +1 -0
  155. package/build/assets/use-handle-plan-click-CUZwmKIk.js +1 -0
  156. package/build/assets/use-is-authed-fNsj-Adj.js +1 -0
  157. package/build/assets/{use-launch-skill-in-chat-3ydwpi_M.js → use-launch-skill-in-chat-ClRJlIx7.js} +1 -1
  158. package/build/assets/use-llm-profiles-CyNVoVqm.js +1 -0
  159. package/build/assets/use-runtime-is-ready-CWkGQFsb.js +1 -0
  160. package/build/assets/{use-save-settings-rE9aA29R.js → use-save-settings-CP23emUY.js} +1 -1
  161. package/build/assets/use-settings-0qFqC-r6.js +1 -0
  162. package/build/assets/{use-settings-nav-items-C7MOWj09.js → use-settings-nav-items-C6YxUn4h.js} +1 -1
  163. package/build/assets/use-skills-BWHATXK-.js +1 -0
  164. package/build/assets/{use-task-list-YMkSzdDv.js → use-task-list-JPudBRv3.js} +1 -1
  165. package/build/assets/{use-tracking-DQYdZpxi.js → use-tracking-CjLZgh8X.js} +1 -1
  166. package/build/assets/use-unified-vscode-url-DSn2tT08.js +1 -0
  167. package/build/assets/use-user-conversation-CQ5IwnZk.js +1 -0
  168. package/build/assets/{useMutation-DDo48A8t.js → useMutation-7hG0GuPx.js} +1 -1
  169. package/build/assets/useQuery-JDs8UaWj.js +1 -0
  170. package/build/assets/{useTranslation-CEcjrme-.js → useTranslation-CbJtty1g.js} +1 -1
  171. package/build/assets/{utils-CdgBzLA7.js → utils-CVcuFUYj.js} +1 -1
  172. package/build/assets/{vendor~browser-DWk6fNtJ.js → vendor~browser-Dwwc84Zf.js} +1 -1
  173. package/build/assets/{vendor~browser-tab-NZdVoI2Z.js → vendor~browser-tab-Bhohe29F.js} +1 -1
  174. package/build/assets/{vendor~conversation-panel~conversation-gp03cWZW.js → vendor~conversation-panel~conversation-DYHL7QoY.js} +1 -1
  175. package/build/assets/{vendor~conversation-panel~conversation~index-BZ5C6Xpz.js → vendor~conversation-panel~conversation~index-Be58Romv.js} +1 -1
  176. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BodGsxSf.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-CBEOG8NF.js} +1 -1
  177. package/build/assets/{vendor~files-tab-Buz36Y-q.js → vendor~files-tab-B447_Zns.js} +1 -1
  178. package/build/assets/{vendor~home~conversation-panel~conversation-DG0H5SkJ.js → vendor~home~conversation-panel~conversation-DZ-F7J6T.js} +1 -1
  179. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CXivI4Ym.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B4oeCCli.js} +1 -1
  180. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-9Il_wz8U.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CQQAW8hY.js} +1 -1
  181. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-1pTajrpX.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DFsI4CLy.js} +1 -1
  182. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ceeqkj0k.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DcvlNgbn.js} +1 -1
  183. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B7I1ZxCx.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-ojk_J4bB.js} +1 -1
  184. package/build/assets/{vendor~launch-DXL78kBf.js → vendor~launch-BdXJCmwc.js} +1 -1
  185. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-CfAc3nMS.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DToubnIU.js} +1 -1
  186. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-DkwcKRtv.js → vendor~root-layout~home~conversation-panel~conversation-Cg0nXqVs.js} +1 -1
  187. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-DSqEbr0N.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-Dr8Ly0at.js} +1 -1
  188. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-BC9XTECT.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-DveauQfg.js} +1 -1
  189. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D0XUSHNN.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~jpfhx3ls-zdl_Rltz.js} +2 -2
  190. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~jxrvuot9-BaCzvZac.js +48 -0
  191. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CcFtthyg.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BwbkftxT.js} +1 -1
  192. package/build/assets/{vendor~root-layout~home~mcp~automations-list-cNHi83v_.js → vendor~root-layout~home~mcp~automations-list-CtdIEhjQ.js} +1 -1
  193. package/build/assets/{vendor~root-layout~home~mcp~automations-list-BnIlGhjl.js → vendor~root-layout~home~mcp~automations-list-DGOI7kQz.js} +1 -1
  194. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BGWUbqUq.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-CbuXadI-.js} +1 -1
  195. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BuCSnjsW.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-iPAfRWNQ.js} +2 -2
  196. package/build/assets/{verification-settings-CIqtxWat.js → verification-settings-Cm02KmeI.js} +1 -1
  197. package/build/assets/{vscode-tab-DEt72yJX.js → vscode-tab-AF70Yke0.js} +1 -1
  198. package/build/assets/{waiting-for-runtime-message-DSjJfeoj.js → waiting-for-runtime-message-Bg27u9JB.js} +1 -1
  199. package/build/assets/x-8AbJWTbX.js +1 -0
  200. package/build/assets/{x-mark-DsJ9tDD0.js → x-mark-Cn-YJVbN.js} +1 -1
  201. package/build/index.html +4 -4
  202. package/build/locales/ar/openhands.json +2 -1
  203. package/build/locales/ca/openhands.json +2 -1
  204. package/build/locales/de/openhands.json +2 -1
  205. package/build/locales/en/openhands.json +2 -1
  206. package/build/locales/es/openhands.json +2 -1
  207. package/build/locales/fr/openhands.json +2 -1
  208. package/build/locales/it/openhands.json +2 -1
  209. package/build/locales/ja/openhands.json +2 -1
  210. package/build/locales/ko-KR/openhands.json +2 -1
  211. package/build/locales/no/openhands.json +2 -1
  212. package/build/locales/pt/openhands.json +2 -1
  213. package/build/locales/tr/openhands.json +2 -1
  214. package/build/locales/uk/openhands.json +2 -1
  215. package/build/locales/zh-CN/openhands.json +2 -1
  216. package/build/locales/zh-TW/openhands.json +2 -1
  217. package/config/defaults.json +1 -1
  218. package/dist/api/agent-server-adapter.cjs +3 -3
  219. package/dist/api/agent-server-adapter.cjs.map +1 -1
  220. package/dist/api/agent-server-adapter.js +94 -86
  221. package/dist/api/agent-server-adapter.js.map +1 -1
  222. package/dist/api/app-preferences-store.cjs.map +1 -1
  223. package/dist/api/app-preferences-store.d.ts +6 -2
  224. package/dist/api/app-preferences-store.js.map +1 -1
  225. package/dist/api/cloud/proxy.cjs +1 -1
  226. package/dist/api/cloud/proxy.cjs.map +1 -1
  227. package/dist/api/cloud/proxy.d.ts +18 -6
  228. package/dist/api/cloud/proxy.js +1 -1
  229. package/dist/api/cloud/proxy.js.map +1 -1
  230. package/dist/api/conversation-metadata-store.cjs.map +1 -1
  231. package/dist/api/conversation-metadata-store.d.ts +8 -0
  232. package/dist/api/conversation-metadata-store.js.map +1 -1
  233. package/dist/api/conversation-service/agent-server-conversation-service.types.d.ts +9 -0
  234. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.cjs +1 -1
  235. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.cjs.map +1 -1
  236. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.js +9 -9
  237. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.js.map +1 -1
  238. package/dist/components/conversation-events/chat/event-message.cjs +1 -1
  239. package/dist/components/conversation-events/chat/event-message.cjs.map +1 -1
  240. package/dist/components/conversation-events/chat/event-message.js +80 -71
  241. package/dist/components/conversation-events/chat/event-message.js.map +1 -1
  242. package/dist/components/features/automations/recommended-automations-launcher.d.ts +7 -1
  243. package/dist/components/features/chat/switch-profile-button.cjs +1 -1
  244. package/dist/components/features/chat/switch-profile-button.cjs.map +1 -1
  245. package/dist/components/features/chat/switch-profile-button.js +5 -5
  246. package/dist/components/features/chat/switch-profile-button.js.map +1 -1
  247. package/dist/components/features/conversation-panel/skills-modal.cjs +1 -1
  248. package/dist/components/features/conversation-panel/skills-modal.cjs.map +1 -1
  249. package/dist/components/features/conversation-panel/skills-modal.js +34 -37
  250. package/dist/components/features/conversation-panel/skills-modal.js.map +1 -1
  251. package/dist/components/features/home/workspace-selection-form.d.ts +1 -0
  252. package/dist/components/features/onboarding/steps/setup-llm-step.d.ts +8 -0
  253. package/dist/components/features/settings/llm-profiles/profile-actions-menu.cjs +1 -1
  254. package/dist/components/features/settings/llm-profiles/profile-actions-menu.js +1 -0
  255. package/dist/components/features/sidebar/sidebar.cjs +1 -1
  256. package/dist/components/features/sidebar/sidebar.js +6 -6
  257. package/dist/components/features/skills/extensions-navigation.cjs +1 -1
  258. package/dist/components/features/skills/extensions-navigation.cjs.map +1 -1
  259. package/dist/components/features/skills/extensions-navigation.d.ts +1 -9
  260. package/dist/components/features/skills/extensions-navigation.js +31 -50
  261. package/dist/components/features/skills/extensions-navigation.js.map +1 -1
  262. package/dist/constants/acp-providers.cjs +1 -1
  263. package/dist/constants/acp-providers.js +1 -1
  264. package/dist/hooks/mutation/use-create-conversation.cjs +1 -1
  265. package/dist/hooks/mutation/use-create-conversation.cjs.map +1 -1
  266. package/dist/hooks/mutation/use-create-conversation.js +26 -14
  267. package/dist/hooks/mutation/use-create-conversation.js.map +1 -1
  268. package/dist/hooks/mutation/use-switch-llm-profile-and-log.cjs +1 -1
  269. package/dist/hooks/mutation/use-switch-llm-profile-and-log.cjs.map +1 -1
  270. package/dist/hooks/mutation/use-switch-llm-profile-and-log.js +26 -15
  271. package/dist/hooks/mutation/use-switch-llm-profile-and-log.js.map +1 -1
  272. package/dist/i18n/declaration.cjs +1 -1
  273. package/dist/i18n/declaration.cjs.map +1 -1
  274. package/dist/i18n/declaration.d.ts +1 -0
  275. package/dist/i18n/declaration.js +1 -1
  276. package/dist/i18n/declaration.js.map +1 -1
  277. package/dist/i18n/translation.cjs +1 -1
  278. package/dist/i18n/translation.cjs.map +1 -1
  279. package/dist/i18n/translation.js +32 -15
  280. package/dist/i18n/translation.js.map +1 -1
  281. package/dist/index.cjs +1 -1
  282. package/dist/index.js +10 -10
  283. package/dist/lib/index.cjs +1 -1
  284. package/dist/lib/index.js +1 -1
  285. package/dist/locales/ar/openhands.json +2 -1
  286. package/dist/locales/ca/openhands.json +2 -1
  287. package/dist/locales/de/openhands.json +2 -1
  288. package/dist/locales/en/openhands.json +2 -1
  289. package/dist/locales/es/openhands.json +2 -1
  290. package/dist/locales/fr/openhands.json +2 -1
  291. package/dist/locales/it/openhands.json +2 -1
  292. package/dist/locales/ja/openhands.json +2 -1
  293. package/dist/locales/ko-KR/openhands.json +2 -1
  294. package/dist/locales/no/openhands.json +2 -1
  295. package/dist/locales/pt/openhands.json +2 -1
  296. package/dist/locales/tr/openhands.json +2 -1
  297. package/dist/locales/uk/openhands.json +2 -1
  298. package/dist/locales/zh-CN/openhands.json +2 -1
  299. package/dist/locales/zh-TW/openhands.json +2 -1
  300. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs +1 -1
  301. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs.map +1 -1
  302. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js +10 -1
  303. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js.map +1 -1
  304. package/dist/package.cjs +1 -1
  305. package/dist/package.cjs.map +1 -1
  306. package/dist/package.js +2 -2
  307. package/dist/package.js.map +1 -1
  308. package/dist/routes/llm-settings.cjs +1 -1
  309. package/dist/routes/llm-settings.cjs.map +1 -1
  310. package/dist/routes/llm-settings.js +21 -21
  311. package/dist/routes/llm-settings.js.map +1 -1
  312. package/dist/routes/mcp.cjs +1 -1
  313. package/dist/routes/mcp.cjs.map +1 -1
  314. package/dist/routes/mcp.d.ts +0 -1
  315. package/dist/routes/mcp.js +0 -1
  316. package/dist/routes/mcp.js.map +1 -1
  317. package/dist/types/agent-server/core/events/index.d.ts +1 -0
  318. package/dist/types/agent-server/core/events/streaming-delta-event.d.ts +7 -0
  319. package/dist/types/agent-server/core/openhands-event.d.ts +2 -2
  320. package/dist/types/agent-server/type-guards.cjs +1 -1
  321. package/dist/types/agent-server/type-guards.cjs.map +1 -1
  322. package/dist/types/agent-server/type-guards.d.ts +2 -0
  323. package/dist/types/agent-server/type-guards.js +3 -3
  324. package/dist/types/agent-server/type-guards.js.map +1 -1
  325. package/dist/utils/handle-event-for-ui.cjs +1 -1
  326. package/dist/utils/handle-event-for-ui.cjs.map +1 -1
  327. package/dist/utils/handle-event-for-ui.js +69 -13
  328. package/dist/utils/handle-event-for-ui.js.map +1 -1
  329. package/dist/utils/mcp-config.cjs +1 -1
  330. package/dist/utils/mcp-config.cjs.map +1 -1
  331. package/dist/utils/mcp-config.js +27 -19
  332. package/dist/utils/mcp-config.js.map +1 -1
  333. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  334. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  335. package/dist/utils/mcp-marketplace-utils.js +38 -18
  336. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  337. package/dist/utils/normalize-display-model.cjs +1 -1
  338. package/dist/utils/normalize-display-model.cjs.map +1 -1
  339. package/dist/utils/normalize-display-model.js +8 -7
  340. package/dist/utils/normalize-display-model.js.map +1 -1
  341. package/dist/utils/openhands-llm.cjs +1 -1
  342. package/dist/utils/openhands-llm.cjs.map +1 -1
  343. package/dist/utils/openhands-llm.d.ts +13 -0
  344. package/dist/utils/openhands-llm.js +9 -3
  345. package/dist/utils/openhands-llm.js.map +1 -1
  346. package/package.json +2 -2
  347. package/scripts/check-sdk-version-sync.mjs +6 -6
  348. package/scripts/dev-safe.mjs +71 -120
  349. package/scripts/dev-with-automation.mjs +58 -4
  350. package/scripts/runtime-services-info.mjs +199 -0
  351. package/scripts/static-server.mjs +42 -4
  352. package/build/assets/acp-providers-DJr8DlNG.js +0 -1
  353. package/build/assets/acp-route-guard-A__sWgbc.js +0 -1
  354. package/build/assets/active-backend-context-I2w666XY.js +0 -1
  355. package/build/assets/add-backend-modal-BDBDBXsJ.js +0 -1
  356. package/build/assets/agent-server-client-options-9agOSarV.js +0 -1
  357. package/build/assets/agent-server-compatibility-B7QStIcH.js +0 -1
  358. package/build/assets/agent-server-conversation-service.api-Cagoqq1V.js +0 -5
  359. package/build/assets/api-key-entry-screen-ByXA4hXH.js +0 -1
  360. package/build/assets/automation-detail-Dbmgt974.js +0 -1
  361. package/build/assets/backend-form-modal-CeB983Sj.js +0 -1
  362. package/build/assets/browser-D08Sp3ZY.js +0 -5
  363. package/build/assets/browser-store-JRrcGdlk.js +0 -1
  364. package/build/assets/chat-send-button-5qz0zj6R.js +0 -1
  365. package/build/assets/check-CZhEL6rP.js +0 -1
  366. package/build/assets/conversation-BrjF2-Ky.js +0 -1
  367. package/build/assets/conversation-HgR_TTPE.js +0 -19
  368. package/build/assets/conversation-panel-BlRcO5AC.js +0 -1
  369. package/build/assets/conversation-service.api-B_Pdmwsa.js +0 -1
  370. package/build/assets/conversation-state-store-D-w0uurj.js +0 -1
  371. package/build/assets/conversation-store-CC-isCnP.js +0 -1
  372. package/build/assets/conversation-websocket-context-G95yfL81.js +0 -3
  373. package/build/assets/dist-Bl-1K5Tv.js +0 -1
  374. package/build/assets/edit-automation-modal-CNZgSSiH.js +0 -1
  375. package/build/assets/extensions-navigation-yFLAU06N.js +0 -1
  376. package/build/assets/files-tab-CMredyYX.js +0 -1
  377. package/build/assets/files-tab-store-DLU28g8C.js +0 -1
  378. package/build/assets/git-control-bar-branch-button-D8blTNXh.js +0 -27
  379. package/build/assets/home-CWw845Rz.js +0 -1
  380. package/build/assets/install-server-modal-D8Q0xZcN.js +0 -1
  381. package/build/assets/llm-client-BqyLKgUN.js +0 -1
  382. package/build/assets/llm-settings-CAnFYAEG.js +0 -1
  383. package/build/assets/llm-settings-DotqpmCF.js +0 -1
  384. package/build/assets/manage-backends-modal-Ceo_SOcf.js +0 -1
  385. package/build/assets/manifest-61ec2d68.js +0 -1
  386. package/build/assets/mcp-EvrLVTla.js +0 -9
  387. package/build/assets/messages-Bz9TWjlh.js +0 -36
  388. package/build/assets/middleware-CfatjPYZ.js +0 -6
  389. package/build/assets/model-selector-CZOi4V7r.js +0 -1
  390. package/build/assets/onboarding-CPCKYvFh.js +0 -1
  391. package/build/assets/organization-service.api-Dn74hBTH.js +0 -1
  392. package/build/assets/path-utils-BjxzIGLp.js +0 -1
  393. package/build/assets/plus-DT-M0FA1.js +0 -1
  394. package/build/assets/profiles-client-BrqNmaDV.js +0 -1
  395. package/build/assets/proxy-sRh0WKI7.js +0 -1
  396. package/build/assets/root-CklXEh3W.js +0 -2
  397. package/build/assets/root-layout-BCA_X8XL.js +0 -2
  398. package/build/assets/secrets-service-DVtlLWY8.js +0 -1
  399. package/build/assets/server-client-DYv_GHPl.js +0 -1
  400. package/build/assets/settings-CXvJUx_j.js +0 -1
  401. package/build/assets/settings-service.api-DxIEtvx6.js +0 -1
  402. package/build/assets/shared-conversation-x41nZQi7.js +0 -1
  403. package/build/assets/sidebar-store-DnQAJAE5.js +0 -1
  404. package/build/assets/telemetry-fQFd-8V3.js +0 -2
  405. package/build/assets/use-agent-settings-schema-Yxf7KGyG.js +0 -1
  406. package/build/assets/use-config-DwfigQ_Y.js +0 -1
  407. package/build/assets/use-create-conversation-BEzddjXn.js +0 -1
  408. package/build/assets/use-event-store-Cxqc45Sw.js +0 -1
  409. package/build/assets/use-get-secrets-BlO1BfUo.js +0 -1
  410. package/build/assets/use-handle-plan-click-Bfl0zIBr.js +0 -1
  411. package/build/assets/use-is-authed-hHndEep7.js +0 -1
  412. package/build/assets/use-llm-profiles-E-jjZMZw.js +0 -1
  413. package/build/assets/use-runtime-is-ready-DBWzvAmc.js +0 -1
  414. package/build/assets/use-settings-BPTbE7lg.js +0 -1
  415. package/build/assets/use-skills-QhoaIYGF.js +0 -1
  416. package/build/assets/use-unified-vscode-url-DFtNIC1Q.js +0 -1
  417. package/build/assets/use-user-conversation-BRAseenw.js +0 -1
  418. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-D8soyAAx.js +0 -48
  419. package/build/assets/vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~jaomi49z-Cw89stA6.js +0 -1
  420. package/build/assets/x-JOBEVLW0.js +0 -1
  421. package/dist/components/features/conversation-panel/skills-runtime-waiting-state.cjs +0 -2
  422. package/dist/components/features/conversation-panel/skills-runtime-waiting-state.cjs.map +0 -1
  423. package/dist/components/features/conversation-panel/skills-runtime-waiting-state.d.ts +0 -1
  424. package/dist/components/features/conversation-panel/skills-runtime-waiting-state.js +0 -21
  425. package/dist/components/features/conversation-panel/skills-runtime-waiting-state.js.map +0 -1
  426. package/dist/utils/acp-route-guard.cjs +0 -1
  427. package/dist/utils/acp-route-guard.d.ts +0 -26
  428. package/dist/utils/acp-route-guard.js +0 -4
  429. /package/build/assets/{agent-server-ui-style-scope-BwIZYdC1.js → agent-server-ui-style-scope-Bhc5vpWO.js} +0 -0
  430. /package/build/assets/{automation-DJ_3GeXD.js → automation-BzmydDjr.js} +0 -0
  431. /package/build/assets/{common-DqjLSBOt.js → common-Cfviy7yT.js} +0 -0
  432. /package/build/assets/{context-CEQZwATj.js → context-BBqptpXX.js} +0 -0
  433. /package/build/assets/{conversation-local-storage-YmOVXxxW.js → conversation-local-storage-D5Tre_GA.js} +0 -0
  434. /package/build/assets/{createLucideIcon-Ddu8jDOQ.js → createLucideIcon-C9OEnwvX.js} +0 -0
  435. /package/build/assets/{environment-switch-store-CiurvTtK.js → environment-switch-store-BpKxp6Xq.js} +0 -0
  436. /package/build/assets/{git-status-mapper-DnL9OC8_.js → git-status-mapper-C3rfzUex.js} +0 -0
  437. /package/build/assets/{handle-capture-consent-3XrjZ8wi.js → handle-capture-consent-DDnXMC9Y.js} +0 -0
  438. /package/build/assets/{health-store-B5f0S2FY.js → health-store-d-d2ssv4.js} +0 -0
  439. /package/build/assets/{iconBase-BVhFI-0E.js → iconBase-1A_WRQ4E.js} +0 -0
  440. /package/build/assets/{map-provider-C3Z5Dx2J.js → map-provider-XSFHmdDs.js} +0 -0
  441. /package/build/assets/{objectWithoutPropertiesLoose-DSQKyRhw.js → objectWithoutPropertiesLoose-B-IA9dU9.js} +0 -0
  442. /package/build/assets/{query-keys-tAsQcc_9.js → query-keys-CQaji0wJ.js} +0 -0
  443. /package/build/assets/{react-Dy05vyj5.js → react-CuAHzoGi.js} +0 -0
  444. /package/build/assets/{retrieve-axios-error-message-BY-yIkIq.js → retrieve-axios-error-message-DbnSBc_1.js} +0 -0
  445. /package/build/assets/{sdk-settings-field-metadata-C6KMD-jZ.js → sdk-settings-field-metadata-CETNItbo.js} +0 -0
  446. /package/build/assets/{settings-DGY6n4J2.js → settings-BgL2HUsU.js} +0 -0
  447. /package/build/assets/{settings-like-page-layout-classes-DNg2vKSM.js → settings-like-page-layout-classes-DENKlZpD.js} +0 -0
  448. /package/build/assets/{use-breakpoint-DpxHDmuH.js → use-breakpoint-Dt2knceC.js} +0 -0
  449. /package/build/assets/{use-click-outside-element-DhxCUyWl.js → use-click-outside-element-Bu2A3s59.js} +0 -0
  450. /package/build/assets/{v4-khGvL7i2.js → v4-BygpdDmc.js} +0 -0
  451. /package/build/assets/{vendor~browser-BDNLFng6.js → vendor~browser-BYEwwJqV.js} +0 -0
  452. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-D_hRW_zc.js → vendor~conversation-panel~conversation~alert-banner-BnHToS5O.js} +0 -0
  453. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~j8sdb9mk-OFpe9fX_.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~j8sdb9mk-oCzr0-9g.js} +0 -0
  454. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BPuuVEqr.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-CTmh4bwd.js} +0 -0
  455. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~skills-settings~m~o9nrx3fm-D44TR8hL.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~skills-settings~m~o9nrx3fm-87v-LliW.js} +0 -0
  456. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dr3Ow7Ms.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-D8cqyq4k.js} +0 -0
  457. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~i4kjfqhl-B1TKKuuH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-DspdqGPW.js} +0 -0
  458. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~e9ykmtgh-Fa-nXZ4M.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~e9ykmtgh-DMH1jSwL.js} +0 -0
  459. /package/build/assets/{vendor~terminal-0ObOedYm.js → vendor~terminal-aeP3PnKf.js} +0 -0
  460. /package/build/assets/{vscode-url-helper-BMq8JBhB.js → vscode-url-helper-DOCkV_-G.js} +0 -0
@@ -3,23 +3,34 @@ import { getAgentServerWorkingDir as t, shouldLoadPublicSkills as n } from "./ag
3
3
  import { getEffectiveLocalBackend as r } from "./backend-registry/active-store.js";
4
4
  import { getAgentServerClientOptions as i } from "./agent-server-client-options.js";
5
5
  import { buildAuthHeaders as a } from "./backend-registry/auth.js";
6
- import { getStoredConversationMetadata as o } from "./conversation-metadata-store.js";
7
- import { DEFAULT_SETTINGS as s } from "../services/settings.js";
8
- import { getAcpProvider as c, resolveEffectiveAcpModel as l } from "../constants/acp-providers.js";
9
- import { isAgentServerToolAvailable as u } from "./agent-server-compatibility.js";
10
- import d from "./settings-service/settings-service.api.js";
6
+ import { ACP_SETTINGS_KEYS as o } from "../node_modules/@openhands/typescript-client/dist/models/acp.js";
7
+ import "../node_modules/@openhands/typescript-client/dist/index.js";
8
+ import { getStoredConversationMetadata as s } from "./conversation-metadata-store.js";
9
+ import { DEFAULT_SETTINGS as c } from "../services/settings.js";
10
+ import { getAcpProvider as l, resolveEffectiveAcpModel as u } from "../constants/acp-providers.js";
11
+ import { isAgentServerToolAvailable as d } from "./agent-server-compatibility.js";
12
+ import f from "./settings-service/settings-service.api.js";
11
13
  //#region src/api/agent-server-adapter.ts
12
- var f = "canvas_ui", p = "canvas_ui_tool", m = [
14
+ var p = "canvas_ui", m = "canvas_ui_tool", h = [
13
15
  "terminal",
14
16
  "file_editor",
15
17
  "task_tracker",
16
- f
17
- ], h = "browser_tool_set", g = "task_tool_set";
18
- function _() {
18
+ p
19
+ ], g = "browser_tool_set", _ = "task_tool_set";
20
+ function v() {
19
21
  return !0;
20
22
  }
21
- function v() {
23
+ function y() {
22
24
  let e = (void 0)?.trim();
25
+ if (e) return e;
26
+ if (typeof window < "u") {
27
+ let e = window.__AGENT_CANVAS_RUNTIME_SERVICES_INFO__;
28
+ if (typeof e == "string") return e.trim() || null;
29
+ }
30
+ return null;
31
+ }
32
+ function b() {
33
+ let e = y();
23
34
  if (!e) return null;
24
35
  try {
25
36
  let t = JSON.parse(e);
@@ -28,8 +39,8 @@ function v() {
28
39
  return null;
29
40
  }
30
41
  }
31
- function y() {
32
- let e = v();
42
+ function x() {
43
+ let e = b();
33
44
  if (!e?.services) return;
34
45
  let t = [];
35
46
  t.push("<RUNTIME_SERVICES>"), e.mode ? t.push(`You are running inside an agent-canvas dev stack started in '${e.mode}' mode.`) : t.push("You are running inside an agent-canvas dev stack."), t.push("The following services are reachable from your sandbox. URLs are written", "from your point of view (i.e., as you should curl/fetch them).", "");
@@ -38,15 +49,15 @@ function y() {
38
49
  let o = n?.url_from_agent;
39
50
  return t.push("", "Trust this block over guessing: do not assume any other URLs are running."), o && t.push(`In particular, ${o} inside your sandbox is the Agent Server`, "you are running inside of — NOT the automation backend."), t.push("</RUNTIME_SERVICES>"), t.join("\n");
40
51
  }
41
- function b(e) {
52
+ function S(e) {
42
53
  let { host: t } = i();
43
54
  return `${t}/api/conversations/${e}`;
44
55
  }
45
- function x(e) {
56
+ function C(e) {
46
57
  return `Conversation ${e.slice(0, 5)}`;
47
58
  }
48
- function S(n) {
49
- let r = o(n.id), a = n.agent?.kind === "ACPAgent", c = a ? n.tags?.acpserver ?? null : null;
59
+ function w(n) {
60
+ let r = s(n.id), a = n.agent?.kind === "ACPAgent", o = a ? n.tags?.acpserver ?? null : null;
50
61
  return {
51
62
  id: n.id,
52
63
  created_by_user_id: null,
@@ -54,17 +65,18 @@ function S(n) {
54
65
  selected_branch: r?.selected_branch ?? null,
55
66
  git_provider: r?.git_provider ?? null,
56
67
  selected_workspace: r?.selected_workspace ?? null,
57
- title: n.title?.trim() ? n.title : x(n.id),
68
+ active_profile: r?.active_profile ?? null,
69
+ title: n.title?.trim() ? n.title : C(n.id),
58
70
  trigger: null,
59
71
  pr_number: [],
60
72
  agent_kind: a ? "acp" : "openhands",
61
- acp_server: c,
62
- llm_model: a ? l({
73
+ acp_server: o,
74
+ llm_model: a ? u({
63
75
  runtimeName: n.current_model_name,
64
76
  runtimeId: n.current_model_id,
65
77
  configured: n.agent?.acp_model,
66
78
  sdkLlm: n.agent?.llm?.model
67
- }) : n.agent?.llm?.model ?? s.llm_model,
79
+ }) : n.agent?.llm?.model ?? c.llm_model,
68
80
  metrics: n.metrics ? {
69
81
  accumulated_cost: n.metrics.accumulated_cost ?? null,
70
82
  max_budget_per_task: n.metrics.max_budget_per_task ?? null,
@@ -81,7 +93,7 @@ function S(n) {
81
93
  updated_at: n.updated_at,
82
94
  execution_status: n.execution_status ?? e.IDLE,
83
95
  sandbox_status: n.sandbox_status ?? null,
84
- conversation_url: b(n.id),
96
+ conversation_url: S(n.id),
85
97
  session_api_key: i().apiKey ?? null,
86
98
  sandbox_id: null,
87
99
  workspace: { working_dir: n.workspace?.working_dir ?? t() },
@@ -89,19 +101,13 @@ function S(n) {
89
101
  sub_conversation_ids: []
90
102
  };
91
103
  }
92
- function C(e) {
104
+ function T(e) {
93
105
  return {
94
- items: e.items.map(S),
106
+ items: e.items.map(w),
95
107
  next_page_id: e.next_page_id ?? null
96
108
  };
97
109
  }
98
- var w = [
99
- "acp_command",
100
- "acp_args",
101
- "acp_model",
102
- "acp_session_mode",
103
- "acp_prompt_timeout"
104
- ], T = "acpserver", E = new Set([
110
+ var E = "acpserver", D = new Set([
105
111
  "schema_version",
106
112
  "agent_settings",
107
113
  "workspace",
@@ -109,22 +115,22 @@ var w = [
109
115
  "initial_message",
110
116
  "plugins"
111
117
  ]);
112
- function D(e) {
118
+ function O(e) {
113
119
  return !e || typeof e != "object" || Array.isArray(e) ? {} : structuredClone(e);
114
120
  }
115
- function O(e) {
121
+ function k(e) {
116
122
  if (typeof e != "string") return;
117
123
  let t = e.trim();
118
124
  return t.length > 0 ? t : void 0;
119
125
  }
120
- function k(e) {
126
+ function A(e) {
121
127
  return e.confirmation_mode === !0 ? e.security_analyzer === "llm" ? {
122
128
  kind: "ConfirmRisky",
123
129
  threshold: "HIGH",
124
130
  confirm_unknown: !0
125
131
  } : { kind: "AlwaysConfirm" } : { kind: "NeverConfirm" };
126
132
  }
127
- function A(e) {
133
+ function j(e) {
128
134
  switch (e.security_analyzer) {
129
135
  case "llm": return { kind: "LLMSecurityAnalyzer" };
130
136
  case "pattern": return { kind: "PatternSecurityAnalyzer" };
@@ -132,30 +138,30 @@ function A(e) {
132
138
  default: return;
133
139
  }
134
140
  }
135
- function j(e) {
141
+ function M(e) {
136
142
  return !!e && typeof e == "object" && !Array.isArray(e) && typeof e.name == "string";
137
143
  }
138
- function M(e, t) {
139
- return e === h ? _() && u(e) : e === g ? t.enable_sub_agents === !0 && u(e) : !0;
144
+ function N(e, t) {
145
+ return e === g ? v() && d(e) : e === _ ? t.enable_sub_agents === !0 && d(e) : !0;
140
146
  }
141
- function N(e) {
147
+ function P(e) {
142
148
  let t = /* @__PURE__ */ new Map();
143
- for (let e of m) t.set(e, {
149
+ for (let e of h) t.set(e, {
144
150
  name: e,
145
151
  params: {}
146
152
  });
147
- for (let n of [h, g]) M(n, e) && t.set(n, {
153
+ for (let n of [g, _]) N(n, e) && t.set(n, {
148
154
  name: n,
149
155
  params: {}
150
156
  });
151
157
  let n = e.tools;
152
- if (Array.isArray(n) && n.every((e) => j(e))) for (let r of n) M(r.name, e) && t.set(r.name, {
158
+ if (Array.isArray(n) && n.every((e) => M(e))) for (let r of n) N(r.name, e) && t.set(r.name, {
153
159
  name: r.name,
154
- params: D(r.params)
160
+ params: O(r.params)
155
161
  });
156
162
  return Array.from(t.values());
157
163
  }
158
- function P(e, t) {
164
+ function F(e, t) {
159
165
  let n = [e?.trim(), t?.trim()].filter(Boolean);
160
166
  return n.length === 0 ? null : {
161
167
  role: "user",
@@ -166,68 +172,70 @@ function P(e, t) {
166
172
  run: !0
167
173
  };
168
174
  }
169
- function F(e) {
170
- let t = y();
175
+ function I(e) {
176
+ let t = x();
171
177
  return {
172
- ...D(e.agent_context),
178
+ ...O(e.agent_context),
173
179
  load_public_skills: n(),
174
180
  load_user_skills: !0,
175
181
  load_project_skills: !0,
176
182
  ...t ? { system_message_suffix: t } : {}
177
183
  };
178
184
  }
179
- function I(e) {
180
- return D(e.agent_settings).agent_kind === "acp";
181
- }
182
185
  function L(e) {
183
- let t = D(e.agent_settings).acp_server;
184
- return typeof t == "string" && t.length > 0 ? t : void 0;
186
+ return O(e.agent_settings).agent_kind === "acp";
185
187
  }
186
188
  function R(e) {
189
+ let t = O(e.agent_settings).acp_server;
190
+ return typeof t == "string" && t.length > 0 ? t : void 0;
191
+ }
192
+ function z(e) {
187
193
  let t = e.acp_command;
188
194
  if (!(Array.isArray(t) && t.length === 0) && t !== void 0) return t;
189
- let n = c(typeof e.acp_server == "string" ? e.acp_server : void 0);
195
+ let n = l(typeof e.acp_server == "string" ? e.acp_server : void 0);
190
196
  return n ? [...n.default_command] : t;
191
197
  }
192
- function z(e) {
193
- let t = D(e.agent_settings), n = {
198
+ function B(e) {
199
+ let t = O(e.agent_settings), n = {
194
200
  agent_kind: "acp",
195
- agent_context: F(t)
201
+ agent_context: I(t)
196
202
  };
197
- for (let e of w) {
198
- if (e === "acp_model") continue;
199
- let r = e === "acp_command" ? R(t) : t[e];
203
+ for (let e of o) {
204
+ if (e === "acp_model" || e === "acp_env") continue;
205
+ let r = e === "acp_command" ? z(t) : t[e];
200
206
  r != null && (n[e] = r);
201
207
  }
202
- let r = c(typeof t.acp_server == "string" ? t.acp_server : void 0), i = l({
208
+ let r = O(t.mcp_config);
209
+ Object.keys(r).length > 0 && "mcpServers" in r && (n.mcp_config = r);
210
+ let i = l(typeof t.acp_server == "string" ? t.acp_server : void 0), a = u({
203
211
  configured: t.acp_model,
204
- providerDefault: r?.default_model
212
+ providerDefault: i?.default_model
205
213
  });
206
- return i && (n.acp_model = i), n;
214
+ return a && (n.acp_model = a), n;
207
215
  }
208
- function B(e) {
209
- let t = D(e.agent_settings), n = D(t.llm);
210
- n.model = typeof n.model == "string" && n.model.trim().length > 0 ? n.model : s.llm_model;
211
- let r = O(n.api_key);
216
+ function V(e) {
217
+ let t = O(e.agent_settings), n = O(t.llm);
218
+ n.model = typeof n.model == "string" && n.model.trim().length > 0 ? n.model : c.llm_model;
219
+ let r = k(n.api_key);
212
220
  r ? n.api_key = r : delete n.api_key;
213
- let i = O(n.base_url);
221
+ let i = k(n.base_url);
214
222
  i ? n.base_url = i : delete n.base_url;
215
- let a = D(t.mcp_config);
223
+ let a = O(t.mcp_config);
216
224
  (Object.keys(a).length === 0 || !("mcpServers" in a)) && delete t.mcp_config, delete t.acp_server;
217
- for (let e of w) delete t[e];
225
+ for (let e of o) delete t[e];
218
226
  return delete t.acp_env, {
219
227
  ...t,
220
228
  llm: n,
221
- agent_context: F(t),
222
- tools: N(t)
229
+ agent_context: I(t),
230
+ tools: P(t)
223
231
  };
224
232
  }
225
- function V(e) {
226
- return I(e) ? z(e) : B(e);
227
- }
228
233
  function H(e) {
229
- let { settings: n, query: r, conversationInstructions: i, plugins: a, workingDir: o } = e, s = D(n.conversation_settings), c = P(r, i);
230
- return E.forEach((e) => delete s[e]), {
234
+ return L(e) ? B(e) : V(e);
235
+ }
236
+ function U(e) {
237
+ let { settings: n, query: r, conversationInstructions: i, plugins: a, workingDir: o } = e, s = O(n.conversation_settings), c = F(r, i);
238
+ return D.forEach((e) => delete s[e]), {
231
239
  ...s,
232
240
  workspace: {
233
241
  kind: "LocalWorkspace",
@@ -241,11 +249,11 @@ function H(e) {
241
249
  })) } : {}
242
250
  };
243
251
  }
244
- function U(e) {
252
+ function W(e) {
245
253
  let t = e.encryptedAgentSettings ? {
246
254
  ...e.settings,
247
255
  agent_settings: e.encryptedAgentSettings
248
- } : e.settings, n = I(t), i = V(t), o = n ? L(t) : void 0, s = H(e.encryptedConversationSettings ? {
256
+ } : e.settings, n = L(t), i = H(t), o = n ? R(t) : void 0, s = U(e.encryptedConversationSettings ? {
249
257
  ...e,
250
258
  settings: {
251
259
  ...e.settings,
@@ -254,16 +262,16 @@ function U(e) {
254
262
  } : e), c = {
255
263
  agent_settings: i,
256
264
  workspace: s.workspace,
257
- confirmation_policy: k(s),
265
+ confirmation_policy: A(s),
258
266
  max_iterations: typeof s.max_iterations == "number" ? s.max_iterations : 500,
259
267
  stuck_detection: !0,
260
268
  autotitle: !0,
261
269
  worktree: !0
262
270
  };
263
- o && (c.tags = { [T]: o }), e.secretsEncrypted && (c.secrets_encrypted = !0), e.conversationId && (c.conversation_id = e.conversationId);
264
- let l = A(s);
271
+ o && (c.tags = { [E]: o }), e.secretsEncrypted && (c.secrets_encrypted = !0), e.conversationId && (c.conversation_id = e.conversationId);
272
+ let l = j(s);
265
273
  if (l && (c.security_analyzer = l), s.initial_message && (c.initial_message = s.initial_message), s.plugins && (c.plugins = s.plugins), s.hook_config && (c.hook_config = s.hook_config), c.tool_module_qualnames = {
266
- [f]: p,
274
+ [p]: m,
267
275
  ...s.tool_module_qualnames ?? {}
268
276
  }, s.agent_definitions && (c.agent_definitions = s.agent_definitions), e.customSecrets && e.customSecrets.length > 0) {
269
277
  let t = r(), i = t ? a(t) : {}, o = {};
@@ -282,9 +290,9 @@ function U(e) {
282
290
  }
283
291
  return c;
284
292
  }
285
- async function W(e) {
286
- let { SecretsService: t } = await import("./secrets-service.js"), [n, r] = await Promise.all([d.getSettingsForConversation(), t.getSecrets()]), { agentSettings: i, conversationSettings: a, secretsEncrypted: o } = n;
287
- return U({
293
+ async function G(e) {
294
+ let { SecretsService: t } = await import("./secrets-service.js"), [n, r] = await Promise.all([f.getSettingsForConversation(), t.getSecrets()]), { agentSettings: i, conversationSettings: a, secretsEncrypted: o } = n;
295
+ return W({
288
296
  ...e,
289
297
  encryptedAgentSettings: i,
290
298
  encryptedConversationSettings: a,
@@ -292,10 +300,10 @@ async function W(e) {
292
300
  customSecrets: r
293
301
  });
294
302
  }
295
- function G() {
303
+ function K() {
296
304
  return { hooks: [] };
297
305
  }
298
306
  //#endregion
299
- export { W as buildStartConversationRequestWithEncryptedSettings, G as emptyHooksResponse, x as getDefaultConversationTitle, S as toAppConversation, C as toConversationPage };
307
+ export { G as buildStartConversationRequestWithEncryptedSettings, K as emptyHooksResponse, C as getDefaultConversationTitle, w as toAppConversation, T as toConversationPage };
300
308
 
301
309
  //# sourceMappingURL=agent-server-adapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-server-adapter.js","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport {\n getAgentServerWorkingDir,\n shouldLoadPublicSkills,\n} from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of `VITE_RUNTIME_SERVICES_INFO` (set by the dev launchers in\n * scripts/dev-*.mjs). All URLs are written from the agent's point of view,\n * not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured dev env var.\n return null;\n }\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n // X-Session-API-Key is the local convention shared by the agent-server\n // and automation backend (see openhands-automation auth.py).\n lines.push(\n ` Auth: header 'X-Session-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nconst ACP_SETTINGS_KEYS = [\n \"acp_command\",\n \"acp_args\",\n \"acp_model\",\n \"acp_session_mode\",\n \"acp_prompt_timeout\",\n] as const;\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n return {\n ...toRecord(agentSettings.agent_context),\n load_public_skills: shouldLoadPublicSkills(),\n load_user_skills: true,\n load_project_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the provider's ``default_model`` so the conversation starts\n // with whatever the Settings → Agent UI shows — without that, the form's\n // displayed default would silently not take effect at runtime until the\n // user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: provider?.default_model,\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" && llm.model.trim().length > 0\n ? llm.model\n : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n // ``acp_env`` is no longer a forwarded ACP setting (provider creds ride the\n // Secrets panel), but a legacy value may linger on persisted settings —\n // scrub it so it never leaks onto the OpenHands payload.\n delete agentSettings.acp_env;\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: true;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n if (options.secretsEncrypted) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = backend ? buildAuthHeaders(backend) : {};\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n\n if (acpMode) {\n payload.agent_settings.agent_context = {\n ...payload.agent_settings.agent_context,\n secrets,\n };\n }\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-server-adapter.js","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { ACP_SETTINGS_KEYS } from \"@openhands/typescript-client\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport {\n getAgentServerWorkingDir,\n shouldLoadPublicSkills,\n} from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of the runtime services info (set by the dev launchers in\n * scripts/dev-*.mjs as `VITE_RUNTIME_SERVICES_INFO`, or injected at serve time\n * by `scripts/static-server.mjs` for static builds — see\n * `getRawRuntimeServicesInfo`). All URLs are written from the agent's point of\n * view, not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\n/**\n * Return the raw runtime-services JSON string, consulting two sources in order\n * (mirrors `getBakedSessionApiKey` in agent-server-config.ts):\n * 1. `VITE_RUNTIME_SERVICES_INFO` — baked into the bundle at build time by\n * the dev launchers (`npm run dev`, dev:static).\n * 2. `window.__AGENT_CANVAS_RUNTIME_SERVICES_INFO__` — injected into\n * index.html at serve time by `scripts/static-server.mjs\n * --runtime-services-info <json>`. This is the path used by static builds\n * (the Docker image and the published binary), where the env var is empty\n * in the prebuilt bundle. Without it the `<RUNTIME_SERVICES>` block is\n * missing and the agent cannot reach the local automation backend.\n */\nfunction getRawRuntimeServicesInfo(): string | null {\n const envRaw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (envRaw) return envRaw;\n\n if (typeof window !== \"undefined\") {\n const injected = (window as unknown as Record<string, unknown>)\n .__AGENT_CANVAS_RUNTIME_SERVICES_INFO__;\n if (typeof injected === \"string\") {\n return injected.trim() || null;\n }\n }\n\n return null;\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = getRawRuntimeServicesInfo();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured env var or\n // injected value.\n return null;\n }\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n // X-Session-API-Key is the local convention shared by the agent-server\n // and automation backend (see openhands-automation auth.py).\n lines.push(\n ` Auth: header 'X-Session-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n active_profile: metadata?.active_profile ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n return {\n ...toRecord(agentSettings.agent_context),\n load_public_skills: shouldLoadPublicSkills(),\n load_user_skills: true,\n load_project_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n // ``acp_env`` is deprecated — provider creds now route via agent_context.secrets.\n if (key === \"acp_env\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // ``mcp_config`` is a *shared* field (not in ACP_SETTINGS_KEYS): forward it\n // so the ACP subprocess connects to the configured MCP servers at session\n // creation. Only include it when it actually carries servers — an empty or\n // malformed value is dropped rather than sending ``mcp_config: {}``.\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length > 0 && \"mcpServers\" in mcpConfig) {\n payload.mcp_config = mcpConfig;\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the provider's ``default_model`` so the conversation starts\n // with whatever the Settings → Agent UI shows — without that, the form's\n // displayed default would silently not take effect at runtime until the\n // user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: provider?.default_model,\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" && llm.model.trim().length > 0\n ? llm.model\n : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n // ``acp_env`` is no longer a forwarded ACP setting (provider creds ride the\n // Secrets panel), but a legacy value may linger on persisted settings —\n // scrub it so it never leaks onto the OpenHands payload.\n delete agentSettings.acp_env;\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: true;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n if (options.secretsEncrypted) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = backend ? buildAuthHeaders(backend) : {};\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n\n if (acpMode) {\n payload.agent_settings.agent_context = {\n ...payload.agent_settings.agent_context,\n secrets,\n };\n }\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"app-preferences-store.cjs","names":[],"sources":["../../src/api/app-preferences-store.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\n/**\n * The local agent-server's PATCH /api/settings only persists\n * `agent_settings_diff` and `conversation_settings_diff`. App-level user\n * preferences (language, sound notifications, analytics consent, git\n * identity) have no native home there, so we persist them in localStorage\n * the same approach `secrets-service.ts` uses for git provider tokens.\n *\n * In cloud mode the cloud backend accepts these fields as flat top-level\n * keys at POST /api/v1/settings, and the cloud fetch returns them. We\n * still write through to localStorage so the values survive momentary\n * fetch failures and so the merge logic in `syncDerivedSettings` has a\n * single source for both modes.\n */\nexport const APP_PREFERENCES_STORAGE_KEY =\n \"openhands-agent-server-app-preferences\";\n\nexport const APP_PREFERENCE_FIELDS = [\n \"language\",\n \"user_consents_to_analytics\",\n \"enable_sound_notifications\",\n \"git_user_name\",\n \"git_user_email\",\n] as const;\n\nexport type AppPreferenceField = (typeof APP_PREFERENCE_FIELDS)[number];\n\nexport type StoredAppPreferences = Partial<Pick<Settings, AppPreferenceField>>;\n\nconst APP_PREFERENCE_FIELD_SET: ReadonlySet<string> = new Set(\n APP_PREFERENCE_FIELDS,\n);\n\nconst isAppPreferenceField = (key: string): key is AppPreferenceField =>\n APP_PREFERENCE_FIELD_SET.has(key);\n\nconst coerceValue = (\n key: AppPreferenceField,\n value: unknown,\n): StoredAppPreferences[AppPreferenceField] | undefined => {\n switch (key) {\n case \"language\":\n case \"git_user_name\":\n case \"git_user_email\":\n return typeof value === \"string\" ? value : undefined;\n case \"enable_sound_notifications\":\n return typeof value === \"boolean\" ? value : undefined;\n case \"user_consents_to_analytics\":\n if (value === null) return null;\n return typeof value === \"boolean\" ? value : undefined;\n default:\n return undefined;\n }\n};\n\nconst sanitize = (input: Record<string, unknown>): StoredAppPreferences => {\n const out: StoredAppPreferences = {};\n for (const key of APP_PREFERENCE_FIELDS) {\n if (key in input) {\n const coerced = coerceValue(key, input[key]);\n if (coerced !== undefined) {\n // TS can't narrow per-key writes through a discriminated assignment,\n // so funnel through a single record write.\n (out as Record<string, unknown>)[key] = coerced;\n }\n }\n }\n return out;\n};\n\nexport const readStoredAppPreferences = (): StoredAppPreferences => {\n if (typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(APP_PREFERENCES_STORAGE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return {};\n }\n return sanitize(parsed as Record<string, unknown>);\n } catch {\n return {};\n }\n};\n\nexport const writeStoredAppPreferences = (\n partial: StoredAppPreferences,\n): void => {\n if (typeof window === \"undefined\") return;\n\n const sanitized = sanitize(partial as Record<string, unknown>);\n const existing = readStoredAppPreferences();\n const merged: StoredAppPreferences = { ...existing, ...sanitized };\n\n if (Object.keys(merged).length === 0) {\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n return;\n }\n\n window.localStorage.setItem(\n APP_PREFERENCES_STORAGE_KEY,\n JSON.stringify(merged),\n );\n};\n\nexport const clearStoredAppPreferences = (): void => {\n if (typeof window === \"undefined\") return;\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n};\n\n/**\n * Split known app-preference keys out of a save payload. Used by\n * `SettingsService.saveSettings` so the local PATCH only ever sees the\n * diff fields the agent-server accepts.\n */\nexport const extractAppPreferences = (\n input: Record<string, unknown>,\n): { extracted: StoredAppPreferences; rest: Record<string, unknown> } => {\n const extracted: StoredAppPreferences = {};\n const rest: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(input)) {\n if (isAppPreferenceField(key)) {\n const coerced = coerceValue(key, value);\n if (coerced !== undefined) {\n (extracted as Record<string, unknown>)[key] = coerced;\n }\n } else {\n rest[key] = value;\n }\n }\n\n return { extracted, rest };\n};\n"],"mappings":"6CAeA,IAAa,EACX,yCAEW,EAAwB,CACnC,WACA,6BACA,6BACA,gBACA,iBACD,CAMK,EAAgD,IAAI,IACxD,EACD,CAEK,EAAwB,GAC5B,EAAyB,IAAI,EAAI,CAE7B,GACJ,EACA,IACyD,CACzD,OAAQ,EAAR,CACE,IAAK,WACL,IAAK,gBACL,IAAK,iBACH,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,GAC7C,IAAK,6BACH,OAAO,OAAO,GAAU,UAAY,EAAQ,IAAA,GAC9C,IAAK,6BAEH,OADI,IAAU,KAAa,KACpB,OAAO,GAAU,UAAY,EAAQ,IAAA,GAC9C,QACE,SAIA,EAAY,GAAyD,CACzE,IAAM,EAA4B,EAAE,CACpC,IAAK,IAAM,KAAO,EAChB,GAAI,KAAO,EAAO,CAChB,IAAM,EAAU,EAAY,EAAK,EAAM,GAAK,CACxC,IAAY,IAAA,KAGb,EAAgC,GAAO,GAI9C,OAAO,GAGI,MAAuD,CAClE,GAAI,OAAO,OAAW,IACpB,MAAO,EAAE,CAGX,GAAI,CACF,IAAM,EAAM,OAAO,aAAa,QAAQ,EAA4B,CACpE,GAAI,CAAC,EAAK,MAAO,EAAE,CACnB,IAAM,EAAS,KAAK,MAAM,EAAI,CAI9B,MAHI,CAAC,GAAU,OAAO,GAAW,UAAY,MAAM,QAAQ,EAAO,CACzD,EAAE,CAEJ,EAAS,EAAkC,MAC5C,CACN,MAAO,EAAE,GAIA,EACX,GACS,CACT,GAAI,OAAO,OAAW,IAAa,OAEnC,IAAM,EAAY,EAAS,EAAmC,CAExD,EAA+B,CAAE,GADtB,GACyB,CAAU,GAAG,EAAW,CAElE,GAAI,OAAO,KAAK,EAAO,CAAC,SAAW,EAAG,CACpC,OAAO,aAAa,WAAW,EAA4B,CAC3D,OAGF,OAAO,aAAa,QAClB,EACA,KAAK,UAAU,EAAO,CACvB,EAaU,EACX,GACuE,CACvE,IAAM,EAAkC,EAAE,CACpC,EAAgC,EAAE,CAExC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAM,CAC9C,GAAI,EAAqB,EAAI,CAAE,CAC7B,IAAM,EAAU,EAAY,EAAK,EAAM,CACnC,IAAY,IAAA,KACb,EAAsC,GAAO,QAGhD,EAAK,GAAO,EAIhB,MAAO,CAAE,YAAW,OAAM"}
1
+ {"version":3,"file":"app-preferences-store.cjs","names":[],"sources":["../../src/api/app-preferences-store.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\n/**\n * The local agent-server's PATCH /api/settings only persists\n * `agent_settings_diff` and `conversation_settings_diff`. App-level user\n * preferences (language, sound notifications, analytics consent, git\n * identity) have no native home in that schema, so we persist them in\n * localStorage as a workaround. This is the same fallback pattern used\n * by `DISABLED_SKILLS_STORAGE_KEY` in `settings-service.api.ts`.\n *\n * In cloud mode the cloud backend accepts these fields as flat top-level\n * keys at POST /api/v1/settings, and the cloud fetch returns them. We\n * still write through to localStorage so the values survive momentary\n * fetch failures and so the merge logic in `syncDerivedSettings` has a\n * single source for both modes.\n *\n * Long-term goal: extend the local agent-server settings schema to cover\n * these fields and delete this module entirely.\n */\nexport const APP_PREFERENCES_STORAGE_KEY =\n \"openhands-agent-server-app-preferences\";\n\nexport const APP_PREFERENCE_FIELDS = [\n \"language\",\n \"user_consents_to_analytics\",\n \"enable_sound_notifications\",\n \"git_user_name\",\n \"git_user_email\",\n] as const;\n\nexport type AppPreferenceField = (typeof APP_PREFERENCE_FIELDS)[number];\n\nexport type StoredAppPreferences = Partial<Pick<Settings, AppPreferenceField>>;\n\nconst APP_PREFERENCE_FIELD_SET: ReadonlySet<string> = new Set(\n APP_PREFERENCE_FIELDS,\n);\n\nconst isAppPreferenceField = (key: string): key is AppPreferenceField =>\n APP_PREFERENCE_FIELD_SET.has(key);\n\nconst coerceValue = (\n key: AppPreferenceField,\n value: unknown,\n): StoredAppPreferences[AppPreferenceField] | undefined => {\n switch (key) {\n case \"language\":\n case \"git_user_name\":\n case \"git_user_email\":\n return typeof value === \"string\" ? value : undefined;\n case \"enable_sound_notifications\":\n return typeof value === \"boolean\" ? value : undefined;\n case \"user_consents_to_analytics\":\n if (value === null) return null;\n return typeof value === \"boolean\" ? value : undefined;\n default:\n return undefined;\n }\n};\n\nconst sanitize = (input: Record<string, unknown>): StoredAppPreferences => {\n const out: StoredAppPreferences = {};\n for (const key of APP_PREFERENCE_FIELDS) {\n if (key in input) {\n const coerced = coerceValue(key, input[key]);\n if (coerced !== undefined) {\n // TS can't narrow per-key writes through a discriminated assignment,\n // so funnel through a single record write.\n (out as Record<string, unknown>)[key] = coerced;\n }\n }\n }\n return out;\n};\n\nexport const readStoredAppPreferences = (): StoredAppPreferences => {\n if (typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(APP_PREFERENCES_STORAGE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return {};\n }\n return sanitize(parsed as Record<string, unknown>);\n } catch {\n return {};\n }\n};\n\nexport const writeStoredAppPreferences = (\n partial: StoredAppPreferences,\n): void => {\n if (typeof window === \"undefined\") return;\n\n const sanitized = sanitize(partial as Record<string, unknown>);\n const existing = readStoredAppPreferences();\n const merged: StoredAppPreferences = { ...existing, ...sanitized };\n\n if (Object.keys(merged).length === 0) {\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n return;\n }\n\n window.localStorage.setItem(\n APP_PREFERENCES_STORAGE_KEY,\n JSON.stringify(merged),\n );\n};\n\nexport const clearStoredAppPreferences = (): void => {\n if (typeof window === \"undefined\") return;\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n};\n\n/**\n * Split known app-preference keys out of a save payload. Used by\n * `SettingsService.saveSettings` so the local PATCH only ever sees the\n * diff fields the agent-server accepts.\n */\nexport const extractAppPreferences = (\n input: Record<string, unknown>,\n): { extracted: StoredAppPreferences; rest: Record<string, unknown> } => {\n const extracted: StoredAppPreferences = {};\n const rest: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(input)) {\n if (isAppPreferenceField(key)) {\n const coerced = coerceValue(key, value);\n if (coerced !== undefined) {\n (extracted as Record<string, unknown>)[key] = coerced;\n }\n } else {\n rest[key] = value;\n }\n }\n\n return { extracted, rest };\n};\n"],"mappings":"6CAmBA,IAAa,EACX,yCAEW,EAAwB,CACnC,WACA,6BACA,6BACA,gBACA,iBACD,CAMK,EAAgD,IAAI,IACxD,EACD,CAEK,EAAwB,GAC5B,EAAyB,IAAI,EAAI,CAE7B,GACJ,EACA,IACyD,CACzD,OAAQ,EAAR,CACE,IAAK,WACL,IAAK,gBACL,IAAK,iBACH,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,GAC7C,IAAK,6BACH,OAAO,OAAO,GAAU,UAAY,EAAQ,IAAA,GAC9C,IAAK,6BAEH,OADI,IAAU,KAAa,KACpB,OAAO,GAAU,UAAY,EAAQ,IAAA,GAC9C,QACE,SAIA,EAAY,GAAyD,CACzE,IAAM,EAA4B,EAAE,CACpC,IAAK,IAAM,KAAO,EAChB,GAAI,KAAO,EAAO,CAChB,IAAM,EAAU,EAAY,EAAK,EAAM,GAAK,CACxC,IAAY,IAAA,KAGb,EAAgC,GAAO,GAI9C,OAAO,GAGI,MAAuD,CAClE,GAAI,OAAO,OAAW,IACpB,MAAO,EAAE,CAGX,GAAI,CACF,IAAM,EAAM,OAAO,aAAa,QAAQ,EAA4B,CACpE,GAAI,CAAC,EAAK,MAAO,EAAE,CACnB,IAAM,EAAS,KAAK,MAAM,EAAI,CAI9B,MAHI,CAAC,GAAU,OAAO,GAAW,UAAY,MAAM,QAAQ,EAAO,CACzD,EAAE,CAEJ,EAAS,EAAkC,MAC5C,CACN,MAAO,EAAE,GAIA,EACX,GACS,CACT,GAAI,OAAO,OAAW,IAAa,OAEnC,IAAM,EAAY,EAAS,EAAmC,CAExD,EAA+B,CAAE,GADtB,GACyB,CAAU,GAAG,EAAW,CAElE,GAAI,OAAO,KAAK,EAAO,CAAC,SAAW,EAAG,CACpC,OAAO,aAAa,WAAW,EAA4B,CAC3D,OAGF,OAAO,aAAa,QAClB,EACA,KAAK,UAAU,EAAO,CACvB,EAaU,EACX,GACuE,CACvE,IAAM,EAAkC,EAAE,CACpC,EAAgC,EAAE,CAExC,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAM,CAC9C,GAAI,EAAqB,EAAI,CAAE,CAC7B,IAAM,EAAU,EAAY,EAAK,EAAM,CACnC,IAAY,IAAA,KACb,EAAsC,GAAO,QAGhD,EAAK,GAAO,EAIhB,MAAO,CAAE,YAAW,OAAM"}
@@ -3,14 +3,18 @@ import { Settings } from "#/types/settings";
3
3
  * The local agent-server's PATCH /api/settings only persists
4
4
  * `agent_settings_diff` and `conversation_settings_diff`. App-level user
5
5
  * preferences (language, sound notifications, analytics consent, git
6
- * identity) have no native home there, so we persist them in localStorage
7
- * the same approach `secrets-service.ts` uses for git provider tokens.
6
+ * identity) have no native home in that schema, so we persist them in
7
+ * localStorage as a workaround. This is the same fallback pattern used
8
+ * by `DISABLED_SKILLS_STORAGE_KEY` in `settings-service.api.ts`.
8
9
  *
9
10
  * In cloud mode the cloud backend accepts these fields as flat top-level
10
11
  * keys at POST /api/v1/settings, and the cloud fetch returns them. We
11
12
  * still write through to localStorage so the values survive momentary
12
13
  * fetch failures and so the merge logic in `syncDerivedSettings` has a
13
14
  * single source for both modes.
15
+ *
16
+ * Long-term goal: extend the local agent-server settings schema to cover
17
+ * these fields and delete this module entirely.
14
18
  */
15
19
  export declare const APP_PREFERENCES_STORAGE_KEY = "openhands-agent-server-app-preferences";
16
20
  export declare const APP_PREFERENCE_FIELDS: readonly ["language", "user_consents_to_analytics", "enable_sound_notifications", "git_user_name", "git_user_email"];
@@ -1 +1 @@
1
- {"version":3,"file":"app-preferences-store.js","names":[],"sources":["../../src/api/app-preferences-store.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\n/**\n * The local agent-server's PATCH /api/settings only persists\n * `agent_settings_diff` and `conversation_settings_diff`. App-level user\n * preferences (language, sound notifications, analytics consent, git\n * identity) have no native home there, so we persist them in localStorage\n * the same approach `secrets-service.ts` uses for git provider tokens.\n *\n * In cloud mode the cloud backend accepts these fields as flat top-level\n * keys at POST /api/v1/settings, and the cloud fetch returns them. We\n * still write through to localStorage so the values survive momentary\n * fetch failures and so the merge logic in `syncDerivedSettings` has a\n * single source for both modes.\n */\nexport const APP_PREFERENCES_STORAGE_KEY =\n \"openhands-agent-server-app-preferences\";\n\nexport const APP_PREFERENCE_FIELDS = [\n \"language\",\n \"user_consents_to_analytics\",\n \"enable_sound_notifications\",\n \"git_user_name\",\n \"git_user_email\",\n] as const;\n\nexport type AppPreferenceField = (typeof APP_PREFERENCE_FIELDS)[number];\n\nexport type StoredAppPreferences = Partial<Pick<Settings, AppPreferenceField>>;\n\nconst APP_PREFERENCE_FIELD_SET: ReadonlySet<string> = new Set(\n APP_PREFERENCE_FIELDS,\n);\n\nconst isAppPreferenceField = (key: string): key is AppPreferenceField =>\n APP_PREFERENCE_FIELD_SET.has(key);\n\nconst coerceValue = (\n key: AppPreferenceField,\n value: unknown,\n): StoredAppPreferences[AppPreferenceField] | undefined => {\n switch (key) {\n case \"language\":\n case \"git_user_name\":\n case \"git_user_email\":\n return typeof value === \"string\" ? value : undefined;\n case \"enable_sound_notifications\":\n return typeof value === \"boolean\" ? value : undefined;\n case \"user_consents_to_analytics\":\n if (value === null) return null;\n return typeof value === \"boolean\" ? value : undefined;\n default:\n return undefined;\n }\n};\n\nconst sanitize = (input: Record<string, unknown>): StoredAppPreferences => {\n const out: StoredAppPreferences = {};\n for (const key of APP_PREFERENCE_FIELDS) {\n if (key in input) {\n const coerced = coerceValue(key, input[key]);\n if (coerced !== undefined) {\n // TS can't narrow per-key writes through a discriminated assignment,\n // so funnel through a single record write.\n (out as Record<string, unknown>)[key] = coerced;\n }\n }\n }\n return out;\n};\n\nexport const readStoredAppPreferences = (): StoredAppPreferences => {\n if (typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(APP_PREFERENCES_STORAGE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return {};\n }\n return sanitize(parsed as Record<string, unknown>);\n } catch {\n return {};\n }\n};\n\nexport const writeStoredAppPreferences = (\n partial: StoredAppPreferences,\n): void => {\n if (typeof window === \"undefined\") return;\n\n const sanitized = sanitize(partial as Record<string, unknown>);\n const existing = readStoredAppPreferences();\n const merged: StoredAppPreferences = { ...existing, ...sanitized };\n\n if (Object.keys(merged).length === 0) {\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n return;\n }\n\n window.localStorage.setItem(\n APP_PREFERENCES_STORAGE_KEY,\n JSON.stringify(merged),\n );\n};\n\nexport const clearStoredAppPreferences = (): void => {\n if (typeof window === \"undefined\") return;\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n};\n\n/**\n * Split known app-preference keys out of a save payload. Used by\n * `SettingsService.saveSettings` so the local PATCH only ever sees the\n * diff fields the agent-server accepts.\n */\nexport const extractAppPreferences = (\n input: Record<string, unknown>,\n): { extracted: StoredAppPreferences; rest: Record<string, unknown> } => {\n const extracted: StoredAppPreferences = {};\n const rest: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(input)) {\n if (isAppPreferenceField(key)) {\n const coerced = coerceValue(key, value);\n if (coerced !== undefined) {\n (extracted as Record<string, unknown>)[key] = coerced;\n }\n } else {\n rest[key] = value;\n }\n }\n\n return { extracted, rest };\n};\n"],"mappings":";AAeA,IAAa,IACX,0CAEW,IAAwB;CACnC;CACA;CACA;CACA;CACA;CACD,EAMK,IAAgD,IAAI,IACxD,EACD,EAEK,KAAwB,MAC5B,EAAyB,IAAI,EAAI,EAE7B,KACJ,GACA,MACyD;AACzD,SAAQ,GAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK,iBACH,QAAO,OAAO,KAAU,WAAW,IAAQ,KAAA;EAC7C,KAAK,6BACH,QAAO,OAAO,KAAU,YAAY,IAAQ,KAAA;EAC9C,KAAK,6BAEH,QADI,MAAU,OAAa,OACpB,OAAO,KAAU,YAAY,IAAQ,KAAA;EAC9C,QACE;;GAIA,KAAY,MAAyD;CACzE,IAAM,IAA4B,EAAE;AACpC,MAAK,IAAM,KAAO,EAChB,KAAI,KAAO,GAAO;EAChB,IAAM,IAAU,EAAY,GAAK,EAAM,GAAK;AAC5C,EAAI,MAAY,KAAA,MAGb,EAAgC,KAAO;;AAI9C,QAAO;GAGI,UAAuD;AAClE,KAAI,OAAO,SAAW,IACpB,QAAO,EAAE;AAGX,KAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,EAA4B;AACpE,MAAI,CAAC,EAAK,QAAO,EAAE;EACnB,IAAM,IAAS,KAAK,MAAM,EAAI;AAI9B,SAHI,CAAC,KAAU,OAAO,KAAW,YAAY,MAAM,QAAQ,EAAO,GACzD,EAAE,GAEJ,EAAS,EAAkC;SAC5C;AACN,SAAO,EAAE;;GAIA,KACX,MACS;AACT,KAAI,OAAO,SAAW,IAAa;CAEnC,IAAM,IAAY,EAAS,EAAmC,EAExD,IAA+B;EAAE,GADtB,GACyB;EAAU,GAAG;EAAW;AAElE,KAAI,OAAO,KAAK,EAAO,CAAC,WAAW,GAAG;AACpC,SAAO,aAAa,WAAW,EAA4B;AAC3D;;AAGF,QAAO,aAAa,QAClB,GACA,KAAK,UAAU,EAAO,CACvB;GAaU,KACX,MACuE;CACvE,IAAM,IAAkC,EAAE,EACpC,IAAgC,EAAE;AAExC,MAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,EAAM,CAC9C,KAAI,EAAqB,EAAI,EAAE;EAC7B,IAAM,IAAU,EAAY,GAAK,EAAM;AACvC,EAAI,MAAY,KAAA,MACb,EAAsC,KAAO;OAGhD,GAAK,KAAO;AAIhB,QAAO;EAAE;EAAW;EAAM"}
1
+ {"version":3,"file":"app-preferences-store.js","names":[],"sources":["../../src/api/app-preferences-store.ts"],"sourcesContent":["import { Settings } from \"#/types/settings\";\n\n/**\n * The local agent-server's PATCH /api/settings only persists\n * `agent_settings_diff` and `conversation_settings_diff`. App-level user\n * preferences (language, sound notifications, analytics consent, git\n * identity) have no native home in that schema, so we persist them in\n * localStorage as a workaround. This is the same fallback pattern used\n * by `DISABLED_SKILLS_STORAGE_KEY` in `settings-service.api.ts`.\n *\n * In cloud mode the cloud backend accepts these fields as flat top-level\n * keys at POST /api/v1/settings, and the cloud fetch returns them. We\n * still write through to localStorage so the values survive momentary\n * fetch failures and so the merge logic in `syncDerivedSettings` has a\n * single source for both modes.\n *\n * Long-term goal: extend the local agent-server settings schema to cover\n * these fields and delete this module entirely.\n */\nexport const APP_PREFERENCES_STORAGE_KEY =\n \"openhands-agent-server-app-preferences\";\n\nexport const APP_PREFERENCE_FIELDS = [\n \"language\",\n \"user_consents_to_analytics\",\n \"enable_sound_notifications\",\n \"git_user_name\",\n \"git_user_email\",\n] as const;\n\nexport type AppPreferenceField = (typeof APP_PREFERENCE_FIELDS)[number];\n\nexport type StoredAppPreferences = Partial<Pick<Settings, AppPreferenceField>>;\n\nconst APP_PREFERENCE_FIELD_SET: ReadonlySet<string> = new Set(\n APP_PREFERENCE_FIELDS,\n);\n\nconst isAppPreferenceField = (key: string): key is AppPreferenceField =>\n APP_PREFERENCE_FIELD_SET.has(key);\n\nconst coerceValue = (\n key: AppPreferenceField,\n value: unknown,\n): StoredAppPreferences[AppPreferenceField] | undefined => {\n switch (key) {\n case \"language\":\n case \"git_user_name\":\n case \"git_user_email\":\n return typeof value === \"string\" ? value : undefined;\n case \"enable_sound_notifications\":\n return typeof value === \"boolean\" ? value : undefined;\n case \"user_consents_to_analytics\":\n if (value === null) return null;\n return typeof value === \"boolean\" ? value : undefined;\n default:\n return undefined;\n }\n};\n\nconst sanitize = (input: Record<string, unknown>): StoredAppPreferences => {\n const out: StoredAppPreferences = {};\n for (const key of APP_PREFERENCE_FIELDS) {\n if (key in input) {\n const coerced = coerceValue(key, input[key]);\n if (coerced !== undefined) {\n // TS can't narrow per-key writes through a discriminated assignment,\n // so funnel through a single record write.\n (out as Record<string, unknown>)[key] = coerced;\n }\n }\n }\n return out;\n};\n\nexport const readStoredAppPreferences = (): StoredAppPreferences => {\n if (typeof window === \"undefined\") {\n return {};\n }\n\n try {\n const raw = window.localStorage.getItem(APP_PREFERENCES_STORAGE_KEY);\n if (!raw) return {};\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return {};\n }\n return sanitize(parsed as Record<string, unknown>);\n } catch {\n return {};\n }\n};\n\nexport const writeStoredAppPreferences = (\n partial: StoredAppPreferences,\n): void => {\n if (typeof window === \"undefined\") return;\n\n const sanitized = sanitize(partial as Record<string, unknown>);\n const existing = readStoredAppPreferences();\n const merged: StoredAppPreferences = { ...existing, ...sanitized };\n\n if (Object.keys(merged).length === 0) {\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n return;\n }\n\n window.localStorage.setItem(\n APP_PREFERENCES_STORAGE_KEY,\n JSON.stringify(merged),\n );\n};\n\nexport const clearStoredAppPreferences = (): void => {\n if (typeof window === \"undefined\") return;\n window.localStorage.removeItem(APP_PREFERENCES_STORAGE_KEY);\n};\n\n/**\n * Split known app-preference keys out of a save payload. Used by\n * `SettingsService.saveSettings` so the local PATCH only ever sees the\n * diff fields the agent-server accepts.\n */\nexport const extractAppPreferences = (\n input: Record<string, unknown>,\n): { extracted: StoredAppPreferences; rest: Record<string, unknown> } => {\n const extracted: StoredAppPreferences = {};\n const rest: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(input)) {\n if (isAppPreferenceField(key)) {\n const coerced = coerceValue(key, value);\n if (coerced !== undefined) {\n (extracted as Record<string, unknown>)[key] = coerced;\n }\n } else {\n rest[key] = value;\n }\n }\n\n return { extracted, rest };\n};\n"],"mappings":";AAmBA,IAAa,IACX,0CAEW,IAAwB;CACnC;CACA;CACA;CACA;CACA;CACD,EAMK,IAAgD,IAAI,IACxD,EACD,EAEK,KAAwB,MAC5B,EAAyB,IAAI,EAAI,EAE7B,KACJ,GACA,MACyD;AACzD,SAAQ,GAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK,iBACH,QAAO,OAAO,KAAU,WAAW,IAAQ,KAAA;EAC7C,KAAK,6BACH,QAAO,OAAO,KAAU,YAAY,IAAQ,KAAA;EAC9C,KAAK,6BAEH,QADI,MAAU,OAAa,OACpB,OAAO,KAAU,YAAY,IAAQ,KAAA;EAC9C,QACE;;GAIA,KAAY,MAAyD;CACzE,IAAM,IAA4B,EAAE;AACpC,MAAK,IAAM,KAAO,EAChB,KAAI,KAAO,GAAO;EAChB,IAAM,IAAU,EAAY,GAAK,EAAM,GAAK;AAC5C,EAAI,MAAY,KAAA,MAGb,EAAgC,KAAO;;AAI9C,QAAO;GAGI,UAAuD;AAClE,KAAI,OAAO,SAAW,IACpB,QAAO,EAAE;AAGX,KAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,EAA4B;AACpE,MAAI,CAAC,EAAK,QAAO,EAAE;EACnB,IAAM,IAAS,KAAK,MAAM,EAAI;AAI9B,SAHI,CAAC,KAAU,OAAO,KAAW,YAAY,MAAM,QAAQ,EAAO,GACzD,EAAE,GAEJ,EAAS,EAAkC;SAC5C;AACN,SAAO,EAAE;;GAIA,KACX,MACS;AACT,KAAI,OAAO,SAAW,IAAa;CAEnC,IAAM,IAAY,EAAS,EAAmC,EAExD,IAA+B;EAAE,GADtB,GACyB;EAAU,GAAG;EAAW;AAElE,KAAI,OAAO,KAAK,EAAO,CAAC,WAAW,GAAG;AACpC,SAAO,aAAa,WAAW,EAA4B;AAC3D;;AAGF,QAAO,aAAa,QAClB,GACA,KAAK,UAAU,EAAO,CACvB;GAaU,KACX,MACuE;CACvE,IAAM,IAAkC,EAAE,EACpC,IAAgC,EAAE;AAExC,MAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,EAAM,CAC9C,KAAI,EAAqB,EAAI,EAAE;EAC7B,IAAM,IAAU,EAAY,GAAK,EAAM;AACvC,EAAI,MAAY,KAAA,MACb,EAAsC,KAAO;OAGhD,GAAK,KAAO;AAIhB,QAAO;EAAE;EAAW;EAAM"}