@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
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@openhands/agent-canvas\",\n \"version\": \"1.0.0-rc.1\",\n \"description\": \"Agent Canvas UI for OpenHands - run AI coding agents with a visual interface\",\n \"license\": \"MIT\",\n \"private\": false,\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/OpenHands/agent-canvas\"\n },\n \"homepage\": \"https://github.com/OpenHands/agent-canvas#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/OpenHands/agent-canvas/issues\"\n },\n \"bin\": {\n \"agent-canvas\": \"bin/agent-canvas.mjs\"\n },\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"dependencies\": {\n \"@heroui/react\": \"2.8.10\",\n \"@microlink/react-json-view\": \"1.31.20\",\n \"@monaco-editor/react\": \"4.7.0\",\n \"@openhands/extensions\": \"git+https://github.com/OpenHands/extensions.git#62594156a187722344736bc2ff5edfb12c0cc75c\",\n \"@openhands/typescript-client\": \"1.24.3\",\n \"@react-router/node\": \"7.14.2\",\n \"@react-router/serve\": \"7.14.2\",\n \"@tailwindcss/vite\": \"4.2.4\",\n \"@tanstack/react-query\": \"5.100.9\",\n \"@types/shell-quote\": \"^1.7.5\",\n \"@uidotdev/usehooks\": \"2.4.1\",\n \"@xterm/addon-fit\": \"0.11.0\",\n \"@xterm/xterm\": \"6.0.0\",\n \"axios\": \"1.16.0\",\n \"class-variance-authority\": \"0.7.1\",\n \"clsx\": \"2.1.1\",\n \"downshift\": \"9.3.2\",\n \"framer-motion\": \"12.38.0\",\n \"i18next\": \"26.0.8\",\n \"i18next-browser-languagedetector\": \"8.2.1\",\n \"i18next-http-backend\": \"4.0.0\",\n \"isbot\": \"5.1.39\",\n \"lucide-react\": \"1.14.0\",\n \"monaco-editor\": \"0.55.1\",\n \"posthog-js\": \"1.372.6\",\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-hot-toast\": \"2.6.0\",\n \"react-i18next\": \"17.0.6\",\n \"react-icons\": \"5.6.0\",\n \"react-markdown\": \"10.1.0\",\n \"react-router\": \"7.14.2\",\n \"react-syntax-highlighter\": \"16.1.1\",\n \"rehype-raw\": \"7.0.0\",\n \"rehype-sanitize\": \"6.0.0\",\n \"remark-breaks\": \"4.0.0\",\n \"remark-gfm\": \"4.0.1\",\n \"shell-quote\": \"^1.8.3\",\n \"sirv-cli\": \"3.0.1\",\n \"socket.io-client\": \"4.8.3\",\n \"tailwind-merge\": \"3.5.0\",\n \"tailwind-scrollbar\": \"4.0.2\",\n \"unist-util-visit\": \"5.1.0\",\n \"uuid\": \"14.0.0\",\n \"vite\": \"8.0.10\",\n \"zustand\": \"5.0.12\"\n },\n \"scripts\": {\n \"dev\": \"node --env-file-if-exists=.env scripts/dev-with-automation.mjs\",\n \"dev:static\": \"node --env-file-if-exists=.env scripts/dev-static.mjs\",\n \"dev:extra-backend\": \"node --env-file-if-exists=.env scripts/dev-extra-backend.mjs\",\n \"dev:minimal\": \"node --env-file-if-exists=.env scripts/dev-safe.mjs\",\n \"dev:frontend\": \"npm run make-i18n && cross-env VITE_MOCK_API=false react-router dev\",\n \"dev:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router dev\",\n \"build\": \"npm run build:app\",\n \"build:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router build\",\n \"start\": \"npx sirv-cli build/ --single\",\n \"test\": \"npm run make-i18n && vitest run\",\n \"test:e2e\": \"playwright test --pass-with-no-tests\",\n \"test:e2e:live\": \"node --env-file-if-exists=.env tests/e2e/live/scripts/run-live-e2e.mjs\",\n \"test:e2e:mock-llm\": \"playwright test --config=playwright.mock-llm.config.ts\",\n \"test:e2e:mock-llm:docker\": \"playwright test --config=playwright.mock-llm-docker.config.ts\",\n \"test:e2e:snapshots\": \"playwright test tests/e2e/snapshots --project=chromium --retries=0\",\n \"test:e2e:snapshots:update\": \"playwright test tests/e2e/snapshots --project=chromium --update-snapshots\",\n \"test:coverage\": \"npm run make-i18n && vitest run --coverage\",\n \"dev_wsl\": \"VITE_WATCH_USE_POLLING=true vite\",\n \"preview\": \"vite preview\",\n \"make-i18n\": \"node scripts/make-i18n-translations.cjs\",\n \"prelint\": \"npm run make-i18n\",\n \"lint\": \"npm run typecheck && eslint src && prettier --check src/**/*.{ts,tsx}\",\n \"lint:fix\": \"eslint src --fix && prettier --write src/**/*.{ts,tsx}\",\n \"prepare\": \"husky\",\n \"typecheck\": \"react-router typegen && tsc\",\n \"typecheck:staged\": \"react-router typegen && npx tsc --noEmit --skipLibCheck\",\n \"check-translation-completeness\": \"node scripts/check-translation-completeness.cjs\",\n \"build:app\": \"npm run make-i18n && react-router build\",\n \"build:lib\": \"npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true VITE_APP_ENV=production vite build && tsc -p tsconfig.lib.json\",\n \"build:docker\": \"node scripts/docker-build.mjs\"\n },\n \"lint-staged\": {\n \"src/**/*.{ts,tsx,js}\": [\n \"eslint --fix\",\n \"prettier --write\"\n ],\n \"src/**/*.{ts,tsx}\": [\n \"bash -c 'npm run typecheck:staged'\"\n ],\n \"src/**/*\": [\n \"npm run check-translation-completeness\"\n ]\n },\n \"devDependencies\": {\n \"@eslint/eslintrc\": \"3.3.1\",\n \"@eslint/js\": \"9.39.4\",\n \"@mswjs/socket.io-binding\": \"0.2.0\",\n \"@playwright/test\": \"1.59.1\",\n \"@react-router/dev\": \"7.14.2\",\n \"@tailwindcss/typography\": \"0.5.19\",\n \"@tanstack/eslint-plugin-query\": \"5.100.9\",\n \"@testing-library/dom\": \"10.4.1\",\n \"@testing-library/jest-dom\": \"6.9.1\",\n \"@testing-library/react\": \"16.3.2\",\n \"@testing-library/user-event\": \"14.6.1\",\n \"@types/mdast\": \"4.0.4\",\n \"@types/node\": \"25.6.0\",\n \"@types/react\": \"19.2.14\",\n \"@types/react-dom\": \"19.2.3\",\n \"@types/react-syntax-highlighter\": \"15.5.13\",\n \"@typescript-eslint/eslint-plugin\": \"8.59.2\",\n \"@typescript-eslint/parser\": \"8.59.2\",\n \"@vercel/react-router\": \"1.3.0\",\n \"@vitest/coverage-v8\": \"4.1.5\",\n \"cross-env\": \"10.1.0\",\n \"eslint\": \"9.39.4\",\n \"eslint-config-prettier\": \"10.1.8\",\n \"eslint-import-resolver-typescript\": \"4.4.4\",\n \"eslint-plugin-i18next\": \"6.1.4\",\n \"eslint-plugin-import-x\": \"4.16.2\",\n \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n \"eslint-plugin-prettier\": \"5.5.5\",\n \"eslint-plugin-react\": \"7.37.5\",\n \"eslint-plugin-react-hooks\": \"7.1.1\",\n \"eslint-plugin-unused-imports\": \"4.4.1\",\n \"globals\": \"16.5.0\",\n \"husky\": \"9.1.7\",\n \"jsdom\": \"29.1.1\",\n \"lint-staged\": \"16.4.0\",\n \"msw\": \"2.14.2\",\n \"postcss-prefix-selector\": \"2.1.1\",\n \"prettier\": \"3.8.3\",\n \"tailwindcss\": \"4.2.4\",\n \"typescript\": \"6.0.3\",\n \"vite-plugin-svgr\": \"5.2.0\",\n \"vitest\": \"4.1.5\"\n },\n \"packageManager\": \"npm@10.5.0\",\n \"volta\": {\n \"node\": \"22.12.0\"\n },\n \"msw\": {\n \"workerDirectory\": [\n \"public\"\n ]\n },\n \"overrides\": {\n \"dompurify\": \"3.3.2\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"bin\",\n \"build\",\n \"config\",\n \"scripts\",\n \"tools\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./browser\": {\n \"types\": \"./dist/components/browser/index.d.ts\",\n \"import\": \"./dist/components/browser/index.js\",\n \"require\": \"./dist/components/browser/index.cjs\"\n },\n \"./conversation\": {\n \"types\": \"./dist/components/conversation/index.d.ts\",\n \"import\": \"./dist/components/conversation/index.js\",\n \"require\": \"./dist/components/conversation/index.cjs\"\n },\n \"./files\": {\n \"types\": \"./dist/components/files/index.d.ts\",\n \"import\": \"./dist/components/files/index.js\",\n \"require\": \"./dist/components/files/index.cjs\"\n },\n \"./settings\": {\n \"types\": \"./dist/components/settings/index.d.ts\",\n \"import\": \"./dist/components/settings/index.js\",\n \"require\": \"./dist/components/settings/index.cjs\"\n },\n \"./sidebar\": {\n \"types\": \"./dist/components/sidebar/index.d.ts\",\n \"import\": \"./dist/components/sidebar/index.js\",\n \"require\": \"./dist/components/sidebar/index.cjs\"\n },\n \"./terminal\": {\n \"types\": \"./dist/components/terminal/index.d.ts\",\n \"import\": \"./dist/components/terminal/index.js\",\n \"require\": \"./dist/components/terminal/index.cjs\"\n },\n \"./i18n\": {\n \"types\": \"./dist/i18n/index.d.ts\",\n \"import\": \"./dist/i18n/index.js\",\n \"require\": \"./dist/i18n/index.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"peerDependencies\": {\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-router\": \"7.14.2\"\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@openhands/agent-canvas\",\n \"version\": \"1.0.0-rc.3\",\n \"description\": \"Agent Canvas UI for OpenHands - run AI coding agents with a visual interface\",\n \"license\": \"MIT\",\n \"private\": false,\n \"type\": \"module\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/OpenHands/agent-canvas\"\n },\n \"homepage\": \"https://github.com/OpenHands/agent-canvas#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/OpenHands/agent-canvas/issues\"\n },\n \"bin\": {\n \"agent-canvas\": \"bin/agent-canvas.mjs\"\n },\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"dependencies\": {\n \"@heroui/react\": \"2.8.10\",\n \"@microlink/react-json-view\": \"1.31.20\",\n \"@monaco-editor/react\": \"4.7.0\",\n \"@openhands/extensions\": \"github:OpenHands/extensions#8a6690071e0e9229ae70b30ff0352aff9e6fca21\",\n \"@openhands/typescript-client\": \"1.24.3\",\n \"@react-router/node\": \"7.14.2\",\n \"@react-router/serve\": \"7.14.2\",\n \"@tailwindcss/vite\": \"4.2.4\",\n \"@tanstack/react-query\": \"5.100.9\",\n \"@types/shell-quote\": \"^1.7.5\",\n \"@uidotdev/usehooks\": \"2.4.1\",\n \"@xterm/addon-fit\": \"0.11.0\",\n \"@xterm/xterm\": \"6.0.0\",\n \"axios\": \"1.16.0\",\n \"class-variance-authority\": \"0.7.1\",\n \"clsx\": \"2.1.1\",\n \"downshift\": \"9.3.2\",\n \"framer-motion\": \"12.38.0\",\n \"i18next\": \"26.0.8\",\n \"i18next-browser-languagedetector\": \"8.2.1\",\n \"i18next-http-backend\": \"4.0.0\",\n \"isbot\": \"5.1.39\",\n \"lucide-react\": \"1.14.0\",\n \"monaco-editor\": \"0.55.1\",\n \"posthog-js\": \"1.372.6\",\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-hot-toast\": \"2.6.0\",\n \"react-i18next\": \"17.0.6\",\n \"react-icons\": \"5.6.0\",\n \"react-markdown\": \"10.1.0\",\n \"react-router\": \"7.14.2\",\n \"react-syntax-highlighter\": \"16.1.1\",\n \"rehype-raw\": \"7.0.0\",\n \"rehype-sanitize\": \"6.0.0\",\n \"remark-breaks\": \"4.0.0\",\n \"remark-gfm\": \"4.0.1\",\n \"shell-quote\": \"^1.8.3\",\n \"sirv-cli\": \"3.0.1\",\n \"socket.io-client\": \"4.8.3\",\n \"tailwind-merge\": \"3.5.0\",\n \"tailwind-scrollbar\": \"4.0.2\",\n \"unist-util-visit\": \"5.1.0\",\n \"uuid\": \"14.0.0\",\n \"vite\": \"8.0.10\",\n \"zustand\": \"5.0.12\"\n },\n \"scripts\": {\n \"dev\": \"node --env-file-if-exists=.env scripts/dev-with-automation.mjs\",\n \"dev:static\": \"node --env-file-if-exists=.env scripts/dev-static.mjs\",\n \"dev:extra-backend\": \"node --env-file-if-exists=.env scripts/dev-extra-backend.mjs\",\n \"dev:minimal\": \"node --env-file-if-exists=.env scripts/dev-safe.mjs\",\n \"dev:frontend\": \"npm run make-i18n && cross-env VITE_MOCK_API=false react-router dev\",\n \"dev:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router dev\",\n \"build\": \"npm run build:app\",\n \"build:mock\": \"npm run make-i18n && cross-env VITE_MOCK_API=true react-router build\",\n \"start\": \"npx sirv-cli build/ --single\",\n \"test\": \"npm run make-i18n && vitest run\",\n \"test:e2e\": \"playwright test --pass-with-no-tests\",\n \"test:e2e:live\": \"node --env-file-if-exists=.env tests/e2e/live/scripts/run-live-e2e.mjs\",\n \"test:e2e:mock-llm\": \"playwright test --config=playwright.mock-llm.config.ts\",\n \"test:e2e:mock-llm:docker\": \"playwright test --config=playwright.mock-llm-docker.config.ts\",\n \"test:e2e:snapshots\": \"playwright test tests/e2e/snapshots --project=chromium --retries=0\",\n \"test:e2e:snapshots:update\": \"playwright test tests/e2e/snapshots --project=chromium --update-snapshots\",\n \"test:coverage\": \"npm run make-i18n && vitest run --coverage\",\n \"dev_wsl\": \"VITE_WATCH_USE_POLLING=true vite\",\n \"preview\": \"vite preview\",\n \"make-i18n\": \"node scripts/make-i18n-translations.cjs\",\n \"prelint\": \"npm run make-i18n\",\n \"lint\": \"npm run typecheck && eslint src && prettier --check src/**/*.{ts,tsx}\",\n \"lint:fix\": \"eslint src --fix && prettier --write src/**/*.{ts,tsx}\",\n \"prepare\": \"husky\",\n \"typecheck\": \"react-router typegen && tsc\",\n \"typecheck:staged\": \"react-router typegen && npx tsc --noEmit --skipLibCheck\",\n \"check-translation-completeness\": \"node scripts/check-translation-completeness.cjs\",\n \"build:app\": \"npm run make-i18n && react-router build\",\n \"build:lib\": \"npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true VITE_APP_ENV=production vite build && tsc -p tsconfig.lib.json\",\n \"build:docker\": \"node scripts/docker-build.mjs\"\n },\n \"lint-staged\": {\n \"src/**/*.{ts,tsx,js}\": [\n \"eslint --fix\",\n \"prettier --write\"\n ],\n \"src/**/*.{ts,tsx}\": [\n \"bash -c 'npm run typecheck:staged'\"\n ],\n \"src/**/*\": [\n \"npm run check-translation-completeness\"\n ]\n },\n \"devDependencies\": {\n \"@eslint/eslintrc\": \"3.3.1\",\n \"@eslint/js\": \"9.39.4\",\n \"@mswjs/socket.io-binding\": \"0.2.0\",\n \"@playwright/test\": \"1.59.1\",\n \"@react-router/dev\": \"7.14.2\",\n \"@tailwindcss/typography\": \"0.5.19\",\n \"@tanstack/eslint-plugin-query\": \"5.100.9\",\n \"@testing-library/dom\": \"10.4.1\",\n \"@testing-library/jest-dom\": \"6.9.1\",\n \"@testing-library/react\": \"16.3.2\",\n \"@testing-library/user-event\": \"14.6.1\",\n \"@types/mdast\": \"4.0.4\",\n \"@types/node\": \"25.6.0\",\n \"@types/react\": \"19.2.14\",\n \"@types/react-dom\": \"19.2.3\",\n \"@types/react-syntax-highlighter\": \"15.5.13\",\n \"@typescript-eslint/eslint-plugin\": \"8.59.2\",\n \"@typescript-eslint/parser\": \"8.59.2\",\n \"@vercel/react-router\": \"1.3.0\",\n \"@vitest/coverage-v8\": \"4.1.5\",\n \"cross-env\": \"10.1.0\",\n \"eslint\": \"9.39.4\",\n \"eslint-config-prettier\": \"10.1.8\",\n \"eslint-import-resolver-typescript\": \"4.4.4\",\n \"eslint-plugin-i18next\": \"6.1.4\",\n \"eslint-plugin-import-x\": \"4.16.2\",\n \"eslint-plugin-jsx-a11y\": \"6.10.2\",\n \"eslint-plugin-prettier\": \"5.5.5\",\n \"eslint-plugin-react\": \"7.37.5\",\n \"eslint-plugin-react-hooks\": \"7.1.1\",\n \"eslint-plugin-unused-imports\": \"4.4.1\",\n \"globals\": \"16.5.0\",\n \"husky\": \"9.1.7\",\n \"jsdom\": \"29.1.1\",\n \"lint-staged\": \"16.4.0\",\n \"msw\": \"2.14.2\",\n \"postcss-prefix-selector\": \"2.1.1\",\n \"prettier\": \"3.8.3\",\n \"tailwindcss\": \"4.2.4\",\n \"typescript\": \"6.0.3\",\n \"vite-plugin-svgr\": \"5.2.0\",\n \"vitest\": \"4.1.5\"\n },\n \"packageManager\": \"npm@10.5.0\",\n \"volta\": {\n \"node\": \"22.12.0\"\n },\n \"msw\": {\n \"workerDirectory\": [\n \"public\"\n ]\n },\n \"overrides\": {\n \"dompurify\": \"3.3.2\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"bin\",\n \"build\",\n \"config\",\n \"scripts\",\n \"tools\"\n ],\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./browser\": {\n \"types\": \"./dist/components/browser/index.d.ts\",\n \"import\": \"./dist/components/browser/index.js\",\n \"require\": \"./dist/components/browser/index.cjs\"\n },\n \"./conversation\": {\n \"types\": \"./dist/components/conversation/index.d.ts\",\n \"import\": \"./dist/components/conversation/index.js\",\n \"require\": \"./dist/components/conversation/index.cjs\"\n },\n \"./files\": {\n \"types\": \"./dist/components/files/index.d.ts\",\n \"import\": \"./dist/components/files/index.js\",\n \"require\": \"./dist/components/files/index.cjs\"\n },\n \"./settings\": {\n \"types\": \"./dist/components/settings/index.d.ts\",\n \"import\": \"./dist/components/settings/index.js\",\n \"require\": \"./dist/components/settings/index.cjs\"\n },\n \"./sidebar\": {\n \"types\": \"./dist/components/sidebar/index.d.ts\",\n \"import\": \"./dist/components/sidebar/index.js\",\n \"require\": \"./dist/components/sidebar/index.cjs\"\n },\n \"./terminal\": {\n \"types\": \"./dist/components/terminal/index.d.ts\",\n \"import\": \"./dist/components/terminal/index.js\",\n \"require\": \"./dist/components/terminal/index.cjs\"\n },\n \"./i18n\": {\n \"types\": \"./dist/i18n/index.d.ts\",\n \"import\": \"./dist/i18n/index.js\",\n \"require\": \"./dist/i18n/index.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"peerDependencies\": {\n \"react\": \"19.2.5\",\n \"react-dom\": \"19.2.5\",\n \"react-router\": \"7.14.2\"\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../i18n/declaration.cjs`);require(`../contexts/active-backend-context.cjs`);const r=require(`../services/settings.cjs`),i=require(`../hooks/query/use-settings.cjs`),a=require(`../components/features/settings/settings-input.cjs`),o=require(`../utils/extract-model-and-provider.cjs`),s=require(`../ui/help-link.cjs`),c=require(`../components/shared/modals/settings/model-selector.cjs`),l=require(`../hooks/query/use-agent-settings-schema.cjs`),u=require(`../components/features/settings/key-status-icon.cjs`),d=require(`../utils/sdk-settings-schema.cjs`),f=require(`../components/features/settings/sdk-settings/sdk-section-page.cjs`),p=require(`../utils/openhands-llm.cjs`);require(`../components/features/settings/llm-profiles/index.cjs`);let m=require(`react`);m=e.__toESM(m,1);let h=require(`react/jsx-runtime`);var g=new Set([`llm.model`,`llm.api_key`,`llm.base_url`]),_=(e,t)=>!e||!t?null:`${e}/${t}`,v=(e,t)=>e?.sections.flatMap(e=>e.fields).find(e=>e.key===t)?.default??null,y={openai:new Set([`https://api.openai.com`,`https://api.openai.com/v1`]),openhands:new Set([p.OPENHANDS_LLM_PROXY_BASE_URL,`https://llm-proxy.app.all-hands.dev/v1`]),litellm_proxy:new Set([p.OPENHANDS_LLM_PROXY_BASE_URL,`https://llm-proxy.app.all-hands.dev/v1`])},b=e=>{try{let t=new URL(e),n=t.pathname.replace(/\/+$/,``)||``;return`${t.origin}${n}`}catch{return e.trim().replace(/\/+$/,``)}},x=(e,t)=>{let n=b(t),{provider:r}=o.extractModelAndProvider(e);if(r){let e=y[r];if(e)return e.has(n)}return Object.values(y).some(e=>e?.has(n))};function S({testId:e}){let{t:r}=t.useTranslation(`openhands`);return(0,h.jsx)(s.HelpLink,{testId:e,text:r(n.I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT),linkText:r(n.I18nKey.SETTINGS$NAV_API_KEYS),href:`https://app.all-hands.dev/settings/api-keys`,suffix:` ${r(n.I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`})}function C({scope:e=`personal`,onSaveSuccess:o,initialValueOverrides:y,embedded:b,hideSaveButton:C,suppressSuccessToast:w,onSaveControlChange:T}){let{t:E}=t.useTranslation(`openhands`),{data:D}=i.useSettings(e),{data:O}=l.useAgentSettingsSchema(D?.agent_settings_schema),k=String(r.DEFAULT_SETTINGS.agent_settings?.llm?.model??``),A=m.default.useCallback((e,t)=>{let n=d.inferInitialView(e,t);if(n!==`basic`)return n;let r=e.llm_model??``,i=e.llm_base_url?.trim()??``;return i.length>0&&!x(r,i)?`all`:`basic`},[]);return(0,h.jsx)(f.SdkSectionPage,{scope:e,sectionKeys:[`llm`],excludeKeys:g,header:m.default.useCallback(({values:e,isDisabled:t,view:r,onChange:i})=>{let o=typeof e[`llm.model`]==`string`?e[`llm.model`]:``,l=typeof e[`llm.base_url`]==`string`?e[`llm.base_url`]:``,d=o.startsWith(`openhands/`),f=typeof e[`llm.api_key`]==`string`?e[`llm.api_key`]:``,p=b?f.length>0:!!D?.llm_api_key_set,m=(e,r)=>(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a.SettingsInput,{testId:e,label:E(n.I18nKey.SETTINGS_FORM$API_KEY),type:`password`,className:`w-full`,value:f,placeholder:p?`<hidden>`:``,onChange:e=>i(`llm.api_key`,e),isDisabled:t,startContent:p?(0,h.jsx)(u.KeyStatusIcon,{isSet:p}):void 0}),(0,h.jsx)(s.HelpLink,{testId:r,text:E(n.I18nKey.SETTINGS$DONT_KNOW_API_KEY),linkText:E(n.I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS),href:`https://docs.openhands.dev/usage/local-setup#getting-an-api-key`})]});return(0,h.jsx)(`div`,{className:`flex flex-col gap-6`,children:r===`basic`?(0,h.jsxs)(`div`,{className:`flex flex-col gap-6`,"data-testid":`llm-settings-form-basic`,children:[(0,h.jsx)(c.ModelSelector,{currentModel:o||void 0,currentBaseUrl:l||void 0,onChange:(e,t)=>{let n=_(e,t);n&&i(`llm.model`,n)},wrapperClassName:`!flex-col !gap-6`,isDisabled:t}),d?(0,h.jsx)(S,{testId:`openhands-api-key-help`}):null,m(`llm-api-key-input`,`llm-api-key-help-anchor`)]}):(0,h.jsxs)(`div`,{className:`flex flex-col gap-6`,"data-testid":`llm-settings-form-advanced`,children:[(0,h.jsx)(a.SettingsInput,{testId:`llm-custom-model-input`,label:E(n.I18nKey.SETTINGS$CUSTOM_MODEL),type:`text`,className:`w-full`,value:o,placeholder:k,onChange:e=>i(`llm.model`,e),isDisabled:t}),d?(0,h.jsx)(S,{testId:`openhands-api-key-help-2`}):null,(0,h.jsx)(a.SettingsInput,{testId:`base-url-input`,label:E(n.I18nKey.SETTINGS$BASE_URL),type:`text`,className:`w-full`,value:l,placeholder:`https://api.openai.com`,onChange:e=>i(`llm.base_url`,e),isDisabled:t}),m(`llm-api-key-input`,`llm-api-key-help-anchor-advanced`)]})})},[k,b,D?.llm_api_key_set,E]),buildPayload:m.default.useCallback((e,t)=>{let n=structuredClone(e),r=n.llm??{};return t.view===`basic`&&(r.base_url=p.isOpenHandsProviderModel(r.model??t.values[`llm.model`])?p.OPENHANDS_LLM_PROXY_BASE_URL:v(O,`llm.base_url`),n.llm=r),{agent_settings_diff:n}},[O]),getInitialView:A,forceShowAdvancedView:!0,allowAllView:!0,onSaveSuccess:o,initialValueOverrides:y,embedded:b,hideSaveButton:C,suppressSuccessToast:w,onSaveControlChange:T,testId:`llm-settings-screen`})}exports.LlmSettingsScreen=C;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../i18n/declaration.cjs`);require(`../contexts/active-backend-context.cjs`);const r=require(`../services/settings.cjs`),i=require(`../hooks/query/use-settings.cjs`),a=require(`../components/features/settings/settings-input.cjs`),o=require(`../utils/extract-model-and-provider.cjs`),s=require(`../ui/help-link.cjs`),c=require(`../utils/openhands-llm.cjs`),l=require(`../components/shared/modals/settings/model-selector.cjs`),u=require(`../hooks/query/use-agent-settings-schema.cjs`),d=require(`../components/features/settings/key-status-icon.cjs`),f=require(`../utils/sdk-settings-schema.cjs`),p=require(`../components/features/settings/sdk-settings/sdk-section-page.cjs`);require(`../components/features/settings/llm-profiles/index.cjs`);let m=require(`react`);m=e.__toESM(m,1);let h=require(`react/jsx-runtime`);var g=new Set([`llm.model`,`llm.api_key`,`llm.base_url`]),_=(e,t)=>!e||!t?null:`${e}/${t}`,v=(e,t)=>e?.sections.flatMap(e=>e.fields).find(e=>e.key===t)?.default??null,y={openai:new Set([`https://api.openai.com`,`https://api.openai.com/v1`]),openhands:new Set([c.OPENHANDS_LLM_PROXY_BASE_URL,`https://llm-proxy.app.all-hands.dev/v1`]),litellm_proxy:new Set([c.OPENHANDS_LLM_PROXY_BASE_URL,`https://llm-proxy.app.all-hands.dev/v1`])},b=e=>{try{let t=new URL(e),n=t.pathname.replace(/\/+$/,``)||``;return`${t.origin}${n}`}catch{return e.trim().replace(/\/+$/,``)}},x=(e,t)=>{let n=b(t),{provider:r}=o.extractModelAndProvider(e);if(r){let e=y[r];if(e)return e.has(n)}return Object.values(y).some(e=>e?.has(n))};function S({testId:e}){let{t:r}=t.useTranslation(`openhands`);return(0,h.jsx)(s.HelpLink,{testId:e,text:r(n.I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT),linkText:r(n.I18nKey.SETTINGS$NAV_API_KEYS),href:`https://app.all-hands.dev/settings/api-keys`,suffix:` ${r(n.I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`})}function C({scope:e=`personal`,onSaveSuccess:o,initialValueOverrides:y,embedded:b,hideSaveButton:C,suppressSuccessToast:w,onSaveControlChange:T}){let{t:E}=t.useTranslation(`openhands`),{data:D}=i.useSettings(e),{data:O}=u.useAgentSettingsSchema(D?.agent_settings_schema),k=String(r.DEFAULT_SETTINGS.agent_settings?.llm?.model??``),A=m.default.useCallback((e,t)=>{let n=f.inferInitialView(e,t);if(n!==`basic`)return n;let r=e.llm_model??``,i=e.llm_base_url?.trim()??``;return i.length>0&&!x(r,i)?`all`:`basic`},[]);return(0,h.jsx)(p.SdkSectionPage,{scope:e,sectionKeys:[`llm`],excludeKeys:g,header:m.default.useCallback(({values:e,isDisabled:t,view:r,onChange:i})=>{let o=typeof e[`llm.model`]==`string`?e[`llm.model`]:``,c=typeof e[`llm.base_url`]==`string`?e[`llm.base_url`]:``,u=o.startsWith(`openhands/`),f=typeof e[`llm.api_key`]==`string`?e[`llm.api_key`]:``,p=b?f.length>0:!!D?.llm_api_key_set,m=(e,r)=>(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a.SettingsInput,{testId:e,label:E(n.I18nKey.SETTINGS_FORM$API_KEY),type:`password`,className:`w-full`,value:f,placeholder:p?`<hidden>`:``,onChange:e=>i(`llm.api_key`,e),isDisabled:t,startContent:p?(0,h.jsx)(d.KeyStatusIcon,{isSet:p}):void 0}),(0,h.jsx)(s.HelpLink,{testId:r,text:E(n.I18nKey.SETTINGS$DONT_KNOW_API_KEY),linkText:E(n.I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS),href:`https://docs.openhands.dev/usage/local-setup#getting-an-api-key`})]});return(0,h.jsx)(`div`,{className:`flex flex-col gap-6`,children:r===`basic`?(0,h.jsxs)(`div`,{className:`flex flex-col gap-6`,"data-testid":`llm-settings-form-basic`,children:[(0,h.jsx)(l.ModelSelector,{currentModel:o||void 0,currentBaseUrl:c||void 0,onChange:(e,t)=>{let n=_(e,t);n&&i(`llm.model`,n)},wrapperClassName:`!flex-col !gap-6`,isDisabled:t}),u?(0,h.jsx)(S,{testId:`openhands-api-key-help`}):null,m(`llm-api-key-input`,`llm-api-key-help-anchor`)]}):(0,h.jsxs)(`div`,{className:`flex flex-col gap-6`,"data-testid":`llm-settings-form-advanced`,children:[(0,h.jsx)(a.SettingsInput,{testId:`llm-custom-model-input`,label:E(n.I18nKey.SETTINGS$CUSTOM_MODEL),type:`text`,className:`w-full`,value:o,placeholder:k,onChange:e=>i(`llm.model`,e),isDisabled:t}),u?(0,h.jsx)(S,{testId:`openhands-api-key-help-2`}):null,(0,h.jsx)(a.SettingsInput,{testId:`base-url-input`,label:E(n.I18nKey.SETTINGS$BASE_URL),type:`text`,className:`w-full`,value:c,placeholder:`https://api.openai.com`,onChange:e=>i(`llm.base_url`,e),isDisabled:t}),m(`llm-api-key-input`,`llm-api-key-help-anchor-advanced`)]})})},[k,b,D?.llm_api_key_set,E]),buildPayload:m.default.useCallback((e,t)=>{let n=structuredClone(e),r=n.llm??{};return t.view===`basic`&&(r.base_url=c.isOpenHandsProxyModel(r.model??t.values[`llm.model`],r.base_url??t.values[`llm.base_url`])?c.OPENHANDS_LLM_PROXY_BASE_URL:v(O,`llm.base_url`),n.llm=r),{agent_settings_diff:n}},[O]),getInitialView:A,forceShowAdvancedView:!0,allowAllView:!0,onSaveSuccess:o,initialValueOverrides:y,embedded:b,hideSaveButton:C,suppressSuccessToast:w,onSaveControlChange:T,testId:`llm-settings-screen`})}exports.LlmSettingsScreen=C;
2
2
  //# sourceMappingURL=llm-settings.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm-settings.cjs","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llm-settings.cjs","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProxyModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n const baseUrl = llm.base_url ?? context.values[\"llm.base_url\"];\n llm.base_url = isOpenHandsProxyModel(model, baseUrl)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
@@ -6,12 +6,12 @@ import { useSettings as r } from "../hooks/query/use-settings.js";
6
6
  import { SettingsInput as i } from "../components/features/settings/settings-input.js";
7
7
  import { extractModelAndProvider as a } from "../utils/extract-model-and-provider.js";
8
8
  import { HelpLink as o } from "../ui/help-link.js";
9
- import { ModelSelector as s } from "../components/shared/modals/settings/model-selector.js";
10
- import { useAgentSettingsSchema as c } from "../hooks/query/use-agent-settings-schema.js";
11
- import { KeyStatusIcon as l } from "../components/features/settings/key-status-icon.js";
12
- import { inferInitialView as u } from "../utils/sdk-settings-schema.js";
13
- import { SdkSectionPage as d } from "../components/features/settings/sdk-settings/sdk-section-page.js";
14
- import { OPENHANDS_LLM_PROXY_BASE_URL as f, isOpenHandsProviderModel as p } from "../utils/openhands-llm.js";
9
+ import { OPENHANDS_LLM_PROXY_BASE_URL as s, isOpenHandsProxyModel as c } from "../utils/openhands-llm.js";
10
+ import { ModelSelector as l } from "../components/shared/modals/settings/model-selector.js";
11
+ import { useAgentSettingsSchema as u } from "../hooks/query/use-agent-settings-schema.js";
12
+ import { KeyStatusIcon as d } from "../components/features/settings/key-status-icon.js";
13
+ import { inferInitialView as f } from "../utils/sdk-settings-schema.js";
14
+ import { SdkSectionPage as p } from "../components/features/settings/sdk-settings/sdk-section-page.js";
15
15
  import "../components/features/settings/llm-profiles/index.js";
16
16
  import m from "react";
17
17
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
@@ -22,8 +22,8 @@ var v = new Set([
22
22
  "llm.base_url"
23
23
  ]), y = (e, t) => !e || !t ? null : `${e}/${t}`, b = (e, t) => e?.sections.flatMap((e) => e.fields).find((e) => e.key === t)?.default ?? null, x = {
24
24
  openai: new Set(["https://api.openai.com", "https://api.openai.com/v1"]),
25
- openhands: new Set([f, "https://llm-proxy.app.all-hands.dev/v1"]),
26
- litellm_proxy: new Set([f, "https://llm-proxy.app.all-hands.dev/v1"])
25
+ openhands: new Set([s, "https://llm-proxy.app.all-hands.dev/v1"]),
26
+ litellm_proxy: new Set([s, "https://llm-proxy.app.all-hands.dev/v1"])
27
27
  }, S = (e) => {
28
28
  try {
29
29
  let t = new URL(e), n = t.pathname.replace(/\/+$/, "") || "";
@@ -50,18 +50,18 @@ function w({ testId: n }) {
50
50
  });
51
51
  }
52
52
  function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S, embedded: T, hideSaveButton: E, suppressSuccessToast: D, onSaveControlChange: O }) {
53
- let { t: k } = e("openhands"), { data: A } = r(a), { data: j } = c(A?.agent_settings_schema), M = String(n.agent_settings?.llm?.model ?? ""), N = m.useCallback((e, t) => {
54
- let n = u(e, t);
53
+ let { t: k } = e("openhands"), { data: A } = r(a), { data: j } = u(A?.agent_settings_schema), M = String(n.agent_settings?.llm?.model ?? ""), N = m.useCallback((e, t) => {
54
+ let n = f(e, t);
55
55
  if (n !== "basic") return n;
56
56
  let r = e.llm_model ?? "", i = e.llm_base_url?.trim() ?? "";
57
57
  return i.length > 0 && !C(r, i) ? "all" : "basic";
58
58
  }, []);
59
- return /* @__PURE__ */ g(d, {
59
+ return /* @__PURE__ */ g(p, {
60
60
  scope: a,
61
61
  sectionKeys: ["llm"],
62
62
  excludeKeys: v,
63
63
  header: m.useCallback(({ values: e, isDisabled: n, view: r, onChange: a }) => {
64
- let c = typeof e["llm.model"] == "string" ? e["llm.model"] : "", u = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", d = c.startsWith("openhands/"), f = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", p = T ? f.length > 0 : !!A?.llm_api_key_set, m = (e, r) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(i, {
64
+ let s = typeof e["llm.model"] == "string" ? e["llm.model"] : "", c = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", u = s.startsWith("openhands/"), f = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", p = T ? f.length > 0 : !!A?.llm_api_key_set, m = (e, r) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(i, {
65
65
  testId: e,
66
66
  label: k(t.SETTINGS_FORM$API_KEY),
67
67
  type: "password",
@@ -70,7 +70,7 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
70
70
  placeholder: p ? "<hidden>" : "",
71
71
  onChange: (e) => a("llm.api_key", e),
72
72
  isDisabled: n,
73
- startContent: p ? /* @__PURE__ */ g(l, { isSet: p }) : void 0
73
+ startContent: p ? /* @__PURE__ */ g(d, { isSet: p }) : void 0
74
74
  }), /* @__PURE__ */ g(o, {
75
75
  testId: r,
76
76
  text: k(t.SETTINGS$DONT_KNOW_API_KEY),
@@ -83,9 +83,9 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
83
83
  className: "flex flex-col gap-6",
84
84
  "data-testid": "llm-settings-form-basic",
85
85
  children: [
86
- /* @__PURE__ */ g(s, {
87
- currentModel: c || void 0,
88
- currentBaseUrl: u || void 0,
86
+ /* @__PURE__ */ g(l, {
87
+ currentModel: s || void 0,
88
+ currentBaseUrl: c || void 0,
89
89
  onChange: (e, t) => {
90
90
  let n = y(e, t);
91
91
  n && a("llm.model", n);
@@ -93,7 +93,7 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
93
93
  wrapperClassName: "!flex-col !gap-6",
94
94
  isDisabled: n
95
95
  }),
96
- d ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help" }) : null,
96
+ u ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help" }) : null,
97
97
  m("llm-api-key-input", "llm-api-key-help-anchor")
98
98
  ]
99
99
  }) : /* @__PURE__ */ _("div", {
@@ -105,18 +105,18 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
105
105
  label: k(t.SETTINGS$CUSTOM_MODEL),
106
106
  type: "text",
107
107
  className: "w-full",
108
- value: c,
108
+ value: s,
109
109
  placeholder: M,
110
110
  onChange: (e) => a("llm.model", e),
111
111
  isDisabled: n
112
112
  }),
113
- d ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help-2" }) : null,
113
+ u ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help-2" }) : null,
114
114
  /* @__PURE__ */ g(i, {
115
115
  testId: "base-url-input",
116
116
  label: k(t.SETTINGS$BASE_URL),
117
117
  type: "text",
118
118
  className: "w-full",
119
- value: u,
119
+ value: c,
120
120
  placeholder: "https://api.openai.com",
121
121
  onChange: (e) => a("llm.base_url", e),
122
122
  isDisabled: n
@@ -133,7 +133,7 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
133
133
  ]),
134
134
  buildPayload: m.useCallback((e, t) => {
135
135
  let n = structuredClone(e), r = n.llm ?? {};
136
- return t.view === "basic" && (r.base_url = p(r.model ?? t.values["llm.model"]) ? f : b(j, "llm.base_url"), n.llm = r), { agent_settings_diff: n };
136
+ return t.view === "basic" && (r.base_url = c(r.model ?? t.values["llm.model"], r.base_url ?? t.values["llm.base_url"]) ? s : b(j, "llm.base_url"), n.llm = r), { agent_settings_diff: n };
137
137
  }, [j]),
138
138
  getInitialView: N,
139
139
  forceShowAdvancedView: !0,
@@ -1 +1 @@
1
- {"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProxyModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n const baseUrl = llm.base_url ?? context.values[\"llm.base_url\"];\n llm.base_url = isOpenHandsProxyModel(model, baseUrl)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../i18n/declaration.cjs`),r=require(`../contexts/active-backend-context.cjs`),i=require(`../utils/custom-toast-handlers.cjs`),a=require(`../utils/mcp-config.cjs`),o=require(`../hooks/query/use-settings.cjs`),s=require(`../components/features/settings/brand-button.cjs`),c=require(`../utils/settings-like-page-layout-classes.cjs`),l=require(`../utils/retrieve-axios-error-message.cjs`),u=require(`../components/features/skills/extensions-navigation.cjs`),d=require(`../components/shared/modals/confirmation-modal.cjs`),f=require(`../hooks/mutation/use-delete-mcp-server.cjs`);require(`../utils/acp-route-guard.cjs`);const p=require(`../utils/mcp-marketplace-utils.cjs`),m=require(`../node_modules/@openhands/extensions/integrations/index.cjs`),h=require(`../utils/mcp-installed-servers.cjs`),g=require(`../components/features/mcp-page/installed-servers-section.cjs`),_=require(`../components/features/mcp-page/marketplace-section.cjs`),v=require(`../components/features/mcp-page/install-server-modal.cjs`),y=require(`../components/features/mcp-page/custom-server-editor.cjs`),b=require(`../components/features/mcp-page/mcp-toolbar.cjs`);require(`../components/features/mcp-page/index.cjs`);let x=require(`react`);x=e.__toESM(x,1);let S=require(`react/jsx-runtime`);function C(){let{t:e}=t.useTranslation(`openhands`),{data:C,isLoading:w}=o.useSettings(),{mutate:T,isPending:E}=f.useDeleteMcpServer(),D=r.useActiveBackend().backend.kind,[O,k]=x.default.useState(null),[A,j]=x.default.useState(null),[M,N]=x.default.useState(null),[P,F]=x.default.useState(``),[I,L]=x.default.useState(`all`),R=h.flattenMcpConfig(a.parseMcpConfig(C?.agent_settings?.mcp_config)),z=p.getMcpMarketplaceCatalog(m.default),B=R.filter(e=>p.installedServerMatchesQuery(e,p.findCatalogEntryForServer(e,z),P)),V=e=>{k(e)};return w||!C?(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsx)(`div`,{className:`flex h-full flex-1 items-center justify-center px-4 md:px-0`,children:(0,S.jsx)(`div`,{className:`h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin`})})]}):(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsxs)(`main`,{className:c.settingsLikeMainScrollClassName,children:[(0,S.jsxs)(`div`,{className:`mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6`,children:[(0,S.jsx)(`div`,{className:`min-w-0`,children:(0,S.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,S.jsxs)(`div`,{className:`space-y-1`,children:[(0,S.jsx)(`h2`,{className:`text-xl font-medium leading-6 text-foreground`,children:e(n.I18nKey.SETTINGS$MCP_TITLE)}),(0,S.jsx)(`div`,{className:`max-w-2xl text-sm text-tertiary-light`,children:e(n.I18nKey.MCP$PAGE_DESCRIPTION)})]}),(0,S.jsx)(s.BrandButton,{type:`button`,variant:`secondary`,testId:`mcp-add-custom-server`,className:`flex-shrink-0 whitespace-nowrap`,onClick:()=>j({id:``,type:`sse`}),children:e(n.I18nKey.MCP$ADD_CUSTOM)})]})}),(0,S.jsx)(b.McpToolbar,{search:P,onSearchChange:F,sectionFilter:I,onSectionFilterChange:L}),I===`library`?null:(0,S.jsxs)(`section`,{className:`flex flex-col gap-3`,children:[(0,S.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e(n.I18nKey.MCP$INSTALLED_TITLE)}),(0,S.jsx)(g.InstalledServersSection,{servers:B,hasAnyInstalled:R.length>0,query:P,onEdit:e=>{j(e)},onDelete:e=>{let t=R.find(t=>t.id===e);t&&N(t)}})]}),I===`installed`?null:(0,S.jsx)(_.MarketplaceSection,{backendKind:D,onSelect:V,onAdd:V,query:P})]}),O&&(0,S.jsx)(v.InstallServerModal,{entry:O,onClose:()=>k(null)}),A&&(0,S.jsx)(y.CustomServerEditor,{server:A,existingServers:R,onClose:()=>j(null)}),M&&(0,S.jsx)(d.ConfirmationModal,{text:e(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>N(null),onConfirm:()=>{M&&T(M,{onSuccess:()=>{i.displaySuccessToast(e(n.I18nKey.MCP$REMOVE_SUCCESS)),N(null)},onError:t=>{i.displayErrorToast(l.retrieveAxiosErrorMessage(t)||e(n.I18nKey.ERROR$GENERIC)),N(null)}})},isConfirming:E})]})]})}exports.default=C;
1
+ const e=require(`../_virtual/_rolldown/runtime.cjs`),t=require(`../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../i18n/declaration.cjs`),r=require(`../contexts/active-backend-context.cjs`),i=require(`../utils/custom-toast-handlers.cjs`),a=require(`../utils/mcp-config.cjs`),o=require(`../hooks/query/use-settings.cjs`),s=require(`../components/features/settings/brand-button.cjs`),c=require(`../utils/settings-like-page-layout-classes.cjs`),l=require(`../utils/retrieve-axios-error-message.cjs`),u=require(`../components/features/skills/extensions-navigation.cjs`),d=require(`../components/shared/modals/confirmation-modal.cjs`),f=require(`../hooks/mutation/use-delete-mcp-server.cjs`),p=require(`../utils/mcp-marketplace-utils.cjs`),m=require(`../node_modules/@openhands/extensions/integrations/index.cjs`),h=require(`../utils/mcp-installed-servers.cjs`),g=require(`../components/features/mcp-page/installed-servers-section.cjs`),_=require(`../components/features/mcp-page/marketplace-section.cjs`),v=require(`../components/features/mcp-page/install-server-modal.cjs`),y=require(`../components/features/mcp-page/custom-server-editor.cjs`),b=require(`../components/features/mcp-page/mcp-toolbar.cjs`);require(`../components/features/mcp-page/index.cjs`);let x=require(`react`);x=e.__toESM(x,1);let S=require(`react/jsx-runtime`);function C(){let{t:e}=t.useTranslation(`openhands`),{data:C,isLoading:w}=o.useSettings(),{mutate:T,isPending:E}=f.useDeleteMcpServer(),D=r.useActiveBackend().backend.kind,[O,k]=x.default.useState(null),[A,j]=x.default.useState(null),[M,N]=x.default.useState(null),[P,F]=x.default.useState(``),[I,L]=x.default.useState(`all`),R=h.flattenMcpConfig(a.parseMcpConfig(C?.agent_settings?.mcp_config)),z=p.getMcpMarketplaceCatalog(m.default),B=R.filter(e=>p.installedServerMatchesQuery(e,p.findCatalogEntryForServer(e,z),P)),V=e=>{k(e)};return w||!C?(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsx)(`div`,{className:`flex h-full flex-1 items-center justify-center px-4 md:px-0`,children:(0,S.jsx)(`div`,{className:`h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin`})})]}):(0,S.jsxs)(`div`,{"data-testid":`mcp-page`,className:`flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10`,children:[(0,S.jsx)(u.ExtensionsNavigation,{}),(0,S.jsxs)(`main`,{className:c.settingsLikeMainScrollClassName,children:[(0,S.jsxs)(`div`,{className:`mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6`,children:[(0,S.jsx)(`div`,{className:`min-w-0`,children:(0,S.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,S.jsxs)(`div`,{className:`space-y-1`,children:[(0,S.jsx)(`h2`,{className:`text-xl font-medium leading-6 text-foreground`,children:e(n.I18nKey.SETTINGS$MCP_TITLE)}),(0,S.jsx)(`div`,{className:`max-w-2xl text-sm text-tertiary-light`,children:e(n.I18nKey.MCP$PAGE_DESCRIPTION)})]}),(0,S.jsx)(s.BrandButton,{type:`button`,variant:`secondary`,testId:`mcp-add-custom-server`,className:`flex-shrink-0 whitespace-nowrap`,onClick:()=>j({id:``,type:`sse`}),children:e(n.I18nKey.MCP$ADD_CUSTOM)})]})}),(0,S.jsx)(b.McpToolbar,{search:P,onSearchChange:F,sectionFilter:I,onSectionFilterChange:L}),I===`library`?null:(0,S.jsxs)(`section`,{className:`flex flex-col gap-3`,children:[(0,S.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e(n.I18nKey.MCP$INSTALLED_TITLE)}),(0,S.jsx)(g.InstalledServersSection,{servers:B,hasAnyInstalled:R.length>0,query:P,onEdit:e=>{j(e)},onDelete:e=>{let t=R.find(t=>t.id===e);t&&N(t)}})]}),I===`installed`?null:(0,S.jsx)(_.MarketplaceSection,{backendKind:D,onSelect:V,onAdd:V,query:P})]}),O&&(0,S.jsx)(v.InstallServerModal,{entry:O,onClose:()=>k(null)}),A&&(0,S.jsx)(y.CustomServerEditor,{server:A,existingServers:R,onClose:()=>j(null)}),M&&(0,S.jsx)(d.ConfirmationModal,{text:e(n.I18nKey.SETTINGS$MCP_CONFIRM_DELETE),onCancel:()=>N(null),onConfirm:()=>{M&&T(M,{onSuccess:()=>{i.displaySuccessToast(e(n.I18nKey.MCP$REMOVE_SUCCESS)),N(null)},onError:t=>{i.displayErrorToast(l.retrieveAxiosErrorMessage(t)||e(n.I18nKey.ERROR$GENERIC)),N(null)}})},isConfirming:E})]})]})}exports.default=C;
2
2
  //# sourceMappingURL=mcp.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.cjs","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// No ACP guard here (unlike `/settings` and `/settings/condenser`): MCP\n// servers configured via `agent_settings.mcp_config` are now forwarded to\n// the ACP subprocess at session creation, so this page is meaningful for\n// both OpenHands and ACP agents. The same editor and `mcp_config` storage\n// drive both kinds.\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1 @@
1
- export declare const clientLoader: () => Promise<Response | null>;
2
1
  export default function MCPPage(): import("react/jsx-runtime").JSX.Element;
@@ -10,7 +10,6 @@ import { retrieveAxiosErrorMessage as l } from "../utils/retrieve-axios-error-me
10
10
  import { ExtensionsNavigation as u } from "../components/features/skills/extensions-navigation.js";
11
11
  import { ConfirmationModal as d } from "../components/shared/modals/confirmation-modal.js";
12
12
  import { useDeleteMcpServer as f } from "../hooks/mutation/use-delete-mcp-server.js";
13
- import "../utils/acp-route-guard.js";
14
13
  import { findCatalogEntryForServer as p, getMcpMarketplaceCatalog as m, installedServerMatchesQuery as h } from "../utils/mcp-marketplace-utils.js";
15
14
  import g from "../node_modules/@openhands/extensions/integrations/index.js";
16
15
  import { flattenMcpConfig as _ } from "../utils/mcp-installed-servers.js";
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport { redirectIfAcpActive } from \"#/utils/acp-route-guard\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// ACP guard: the ACP sub-agent owns its own MCP server configuration —\n// the SDK explicitly rejects `mcp_config` on ACPAgent init, and\n// `agent-server-adapter` already strips it from start payloads. The\n// Settings → Agent page is where the user configures the ACP server, so\n// bouncing there is consistent with how `/settings` and\n// `/settings/condenser` already behave under ACP.\n//\n// Declared with no parameters (rather than typed as Route.ClientLoaderArgs)\n// so the lib build doesn't pull generated React Router types out of rootDir.\nexport const clientLoader = async () => redirectIfAcpActive();\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.js","names":[],"sources":["../../src/routes/mcp.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { ExtensionsNavigation } from \"#/components/features/skills/extensions-navigation\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { parseMcpConfig } from \"#/utils/mcp-config\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { settingsLikeMainScrollClassName } from \"#/utils/settings-like-page-layout-classes\";\nimport {\n findCatalogEntryForServer,\n getMcpMarketplaceCatalog,\n installedServerMatchesQuery,\n} from \"#/utils/mcp-marketplace-utils\";\nimport {\n INTEGRATION_CATALOG as MCP_MARKETPLACE,\n type IntegrationCatalogEntry as MarketplaceEntry,\n} from \"@openhands/extensions/integrations\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { flattenMcpConfig } from \"#/utils/mcp-installed-servers\";\nimport {\n InstalledServersSection,\n McpToolbar,\n MarketplaceSection,\n InstallServerModal,\n CustomServerEditor,\n type McpSectionFilter,\n} from \"#/components/features/mcp-page\";\n\n// No ACP guard here (unlike `/settings` and `/settings/condenser`): MCP\n// servers configured via `agent_settings.mcp_config` are now forwarded to\n// the ACP subprocess at session creation, so this page is meaningful for\n// both OpenHands and ACP agents. The same editor and `mcp_config` storage\n// drive both kinds.\n\nexport default function MCPPage() {\n const { t } = useTranslation(\"openhands\");\n const { data: settings, isLoading } = useSettings();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const activeBackend = useActiveBackend();\n const backendKind = activeBackend.backend.kind;\n\n const [installEntry, setInstallEntry] =\n React.useState<MarketplaceEntry | null>(null);\n const [editingServer, setEditingServer] =\n React.useState<MCPServerConfig | null>(null);\n const [serverToDelete, setServerToDelete] =\n React.useState<MCPServerConfig | null>(null);\n const [searchQuery, setSearchQuery] = React.useState(\"\");\n const [sectionFilter, setSectionFilter] =\n React.useState<McpSectionFilter>(\"all\");\n\n const mcpConfig = parseMcpConfig(settings?.agent_settings?.mcp_config);\n const allServers = flattenMcpConfig(mcpConfig);\n const mcpMarketplace = getMcpMarketplaceCatalog(MCP_MARKETPLACE);\n\n // Filter installed servers by the search query. We pair each server\n // with its catalog entry (if any) so the search can match friendly\n // names like \"Slack\" against a stdio server whose own `.name` is\n // just \"slack\".\n const filteredInstalledServers = allServers.filter((server) =>\n installedServerMatchesQuery(\n server,\n findCatalogEntryForServer(server, mcpMarketplace),\n searchQuery,\n ),\n );\n\n const handleMarketplaceInstall = (entry: MarketplaceEntry) => {\n setInstallEntry(entry);\n };\n\n const handleEdit = (server: MCPServerConfig) => {\n setEditingServer(server);\n };\n\n const handleDeleteClick = (serverId: string) => {\n const target = allServers.find((s) => s.id === serverId);\n if (target) setServerToDelete(target);\n };\n\n const handleConfirmDelete = () => {\n if (!serverToDelete) return;\n // Pass the full server config — useDeleteMcpServer re-resolves its\n // position against the fresh settings at mutation time, so a\n // background refresh between this click and confirm cannot point\n // us at the wrong index.\n deleteMcpServer(serverToDelete, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setServerToDelete(null);\n },\n onError: (err) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n setServerToDelete(null);\n },\n });\n };\n\n if (isLoading || !settings) {\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <div className=\"flex h-full flex-1 items-center justify-center px-4 md:px-0\">\n <div className=\"h-8 w-8 rounded-full border-2 border-[var(--oh-border)] border-t-white animate-spin\" />\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-testid=\"mcp-page\"\n className=\"flex h-full gap-4 md:gap-6 md:pl-8 lg:gap-10 lg:pl-10\"\n >\n <ExtensionsNavigation />\n <main className={settingsLikeMainScrollClassName}>\n <div className=\"mx-auto flex w-full min-w-0 max-w-[800px] flex-col gap-6\">\n <div className=\"min-w-0\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-xl font-medium leading-6 text-foreground\">\n {t(I18nKey.SETTINGS$MCP_TITLE)}\n </h2>\n <div className=\"max-w-2xl text-sm text-tertiary-light\">\n {t(I18nKey.MCP$PAGE_DESCRIPTION)}\n </div>\n </div>\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n testId=\"mcp-add-custom-server\"\n className=\"flex-shrink-0 whitespace-nowrap\"\n onClick={() => setEditingServer({ id: \"\", type: \"sse\" })}\n >\n {t(I18nKey.MCP$ADD_CUSTOM)}\n </BrandButton>\n </div>\n </div>\n\n <McpToolbar\n search={searchQuery}\n onSearchChange={setSearchQuery}\n sectionFilter={sectionFilter}\n onSectionFilterChange={setSectionFilter}\n />\n\n {sectionFilter !== \"library\" ? (\n <section className=\"flex flex-col gap-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(I18nKey.MCP$INSTALLED_TITLE)}\n </h2>\n <InstalledServersSection\n servers={filteredInstalledServers}\n hasAnyInstalled={allServers.length > 0}\n query={searchQuery}\n onEdit={handleEdit}\n onDelete={handleDeleteClick}\n />\n </section>\n ) : null}\n\n {sectionFilter !== \"installed\" ? (\n <MarketplaceSection\n backendKind={backendKind}\n onSelect={handleMarketplaceInstall}\n onAdd={handleMarketplaceInstall}\n query={searchQuery}\n />\n ) : null}\n </div>\n\n {installEntry && (\n <InstallServerModal\n entry={installEntry}\n onClose={() => setInstallEntry(null)}\n />\n )}\n\n {/* Custom (or non-marketplace) server editor. The empty-id\n sentinel (`{ id: \"\", type: \"sse\" }`) means \"add new\". */}\n {editingServer && (\n <CustomServerEditor\n server={editingServer}\n existingServers={allServers}\n onClose={() => setEditingServer(null)}\n />\n )}\n\n {serverToDelete && (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setServerToDelete(null)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n )}\n </main>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -6,4 +6,5 @@ export * from "./hook-execution-event";
6
6
  export * from "./message-event";
7
7
  export * from "./observation-event";
8
8
  export * from "./pause-event";
9
+ export * from "./streaming-delta-event";
9
10
  export * from "./system-event";
@@ -0,0 +1,7 @@
1
+ import { BaseEvent } from "../base/event";
2
+ export interface StreamingDeltaEvent extends BaseEvent {
3
+ kind: "StreamingDeltaEvent";
4
+ source: "agent";
5
+ content: string | null;
6
+ reasoning_content: string | null;
7
+ }
@@ -1,6 +1,6 @@
1
- import { ACPToolCallEvent, ActionEvent, MessageEvent, ObservationEvent, UserRejectObservation, AgentErrorEvent, SystemPromptEvent, CondensationEvent, CondensationRequestEvent, CondensationSummaryEvent, ConversationStateUpdateEvent, ConversationErrorEvent, HookExecutionEvent, PauseEvent, ServerErrorEvent } from "./events/index";
1
+ import { ACPToolCallEvent, ActionEvent, MessageEvent, ObservationEvent, UserRejectObservation, AgentErrorEvent, SystemPromptEvent, CondensationEvent, CondensationRequestEvent, CondensationSummaryEvent, ConversationStateUpdateEvent, ConversationErrorEvent, HookExecutionEvent, PauseEvent, ServerErrorEvent, StreamingDeltaEvent } from "./events/index";
2
2
  /**
3
3
  * Union type representing all possible OpenHands events.
4
4
  * This includes all main event types that can occur in the system.
5
5
  */
6
- export type OpenHandsEvent = ActionEvent | MessageEvent | ObservationEvent | UserRejectObservation | AgentErrorEvent | SystemPromptEvent | ACPToolCallEvent | HookExecutionEvent | CondensationEvent | CondensationRequestEvent | CondensationSummaryEvent | ConversationStateUpdateEvent | ConversationErrorEvent | PauseEvent | ServerErrorEvent;
6
+ export type OpenHandsEvent = ActionEvent | MessageEvent | ObservationEvent | UserRejectObservation | AgentErrorEvent | SystemPromptEvent | ACPToolCallEvent | HookExecutionEvent | CondensationEvent | CondensationRequestEvent | CondensationSummaryEvent | ConversationStateUpdateEvent | ConversationErrorEvent | PauseEvent | ServerErrorEvent | StreamingDeltaEvent;
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);function e(e){return typeof e==`object`&&!!e&&`id`in e&&`timestamp`in e&&`source`in e&&typeof e.id==`string`&&e.id.length>0&&typeof e.timestamp==`string`&&e.timestamp.length>0&&typeof e.source==`string`&&(e.source===`agent`||e.source===`user`||e.source===`environment`||e.source===`hook`)}var t=e=>e.source===`environment`&&`action_id`in e&&`observation`in e&&e.observation!==null&&typeof e.observation==`object`&&`kind`in e.observation,n=e=>e.source===`agent`&&`tool_name`in e&&`tool_call_id`in e&&`error`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`&&typeof e.error==`string`,r=e=>`llm_message`in e&&typeof e.llm_message==`object`&&e.llm_message!==null&&`role`in e.llm_message&&`content`in e.llm_message,i=e=>r(e)&&e.llm_message.role===`user`,a=e=>e.source===`agent`&&`action`in e&&e.action!==null&&typeof e.action==`object`&&`kind`in e.action&&`tool_name`in e&&`tool_call_id`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`,o=e=>a(e)&&(e.action.kind===`ExecuteBashAction`||e.action.kind===`TerminalAction`),s=e=>t(e)&&(e.observation.kind===`ExecuteBashObservation`||e.observation.kind===`TerminalObservation`),c=e=>t(e)&&e.observation.kind===`PlanningFileEditorObservation`,l=e=>t(e)&&e.observation.kind===`BrowserObservation`,u=e=>t(e)&&e.observation.kind===`SwitchLLMObservation`,d=e=>a(e)&&e.action.kind===`BrowserNavigateAction`,f=e=>a(e)&&e.tool_name===`canvas_ui`,p=e=>e.source===`agent`&&`system_prompt`in e&&`tools`in e&&typeof e.system_prompt==`object`&&Array.isArray(e.tools),m=e=>`kind`in e&&e.kind===`ConversationStateUpdateEvent`,h=e=>e.key===`full_state`,g=e=>e.key===`execution_status`,_=e=>e.key===`stats`,v=e=>`kind`in e&&e.kind===`ConversationErrorEvent`,y=e=>`kind`in e&&e.kind===`ServerErrorEvent`,b=e=>v(e)||y(e),x=e=>`kind`in e&&e.kind===`HookExecutionEvent`,S=e=>`kind`in e&&e.kind===`ACPToolCallEvent`;function C(t){return e(t)}exports.isACPToolCallEvent=S,exports.isActionEvent=a,exports.isAgentErrorEvent=n,exports.isAgentServerEvent=C,exports.isAgentStatusConversationStateUpdateEvent=g,exports.isBrowserNavigateActionEvent=d,exports.isBrowserObservationEvent=l,exports.isCanvasUIActionEvent=f,exports.isConversationStateUpdateEvent=m,exports.isDisplayableErrorEvent=b,exports.isExecuteBashActionEvent=o,exports.isExecuteBashObservationEvent=s,exports.isFullStateConversationStateUpdateEvent=h,exports.isHookExecutionEvent=x,exports.isMessageEvent=r,exports.isObservationEvent=t,exports.isPlanningFileEditorObservationEvent=c,exports.isStatsConversationStateUpdateEvent=_,exports.isSwitchLLMObservationEvent=u,exports.isSystemPromptEvent=p,exports.isUserMessageEvent=i;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);function e(e){return typeof e==`object`&&!!e&&`id`in e&&`timestamp`in e&&`source`in e&&typeof e.id==`string`&&e.id.length>0&&typeof e.timestamp==`string`&&e.timestamp.length>0&&typeof e.source==`string`&&(e.source===`agent`||e.source===`user`||e.source===`environment`||e.source===`hook`)}var t=e=>e.source===`environment`&&`action_id`in e&&`observation`in e&&e.observation!==null&&typeof e.observation==`object`&&`kind`in e.observation,n=e=>e.source===`agent`&&`tool_name`in e&&`tool_call_id`in e&&`error`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`&&typeof e.error==`string`,r=e=>`llm_message`in e&&typeof e.llm_message==`object`&&e.llm_message!==null&&`role`in e.llm_message&&`content`in e.llm_message,i=e=>r(e)&&e.llm_message.role===`user`,a=e=>e.source===`agent`&&`action`in e&&e.action!==null&&typeof e.action==`object`&&`kind`in e.action&&`tool_name`in e&&`tool_call_id`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`,o=e=>a(e)&&(e.action.kind===`ExecuteBashAction`||e.action.kind===`TerminalAction`),s=e=>t(e)&&(e.observation.kind===`ExecuteBashObservation`||e.observation.kind===`TerminalObservation`),c=e=>t(e)&&e.observation.kind===`PlanningFileEditorObservation`,l=e=>t(e)&&e.observation.kind===`BrowserObservation`,u=e=>t(e)&&e.observation.kind===`SwitchLLMObservation`,d=e=>a(e)&&e.action.kind===`BrowserNavigateAction`,f=e=>a(e)&&e.tool_name===`canvas_ui`,p=e=>e.source===`agent`&&`system_prompt`in e&&`tools`in e&&typeof e.system_prompt==`object`&&Array.isArray(e.tools),m=e=>`kind`in e&&e.kind===`ConversationStateUpdateEvent`,h=e=>e.key===`full_state`,g=e=>e.key===`execution_status`,_=e=>e.key===`stats`,v=e=>`kind`in e&&e.kind===`ConversationErrorEvent`,y=e=>`kind`in e&&e.kind===`ServerErrorEvent`,b=e=>v(e)||y(e),x=e=>`kind`in e&&e.kind===`HookExecutionEvent`,S=e=>`kind`in e&&e.kind===`ACPToolCallEvent`,C=e=>`kind`in e&&e.kind===`StreamingDeltaEvent`;function w(t){return e(t)}exports.isACPToolCallEvent=S,exports.isActionEvent=a,exports.isAgentErrorEvent=n,exports.isAgentServerEvent=w,exports.isAgentStatusConversationStateUpdateEvent=g,exports.isBrowserNavigateActionEvent=d,exports.isBrowserObservationEvent=l,exports.isCanvasUIActionEvent=f,exports.isConversationStateUpdateEvent=m,exports.isDisplayableErrorEvent=b,exports.isExecuteBashActionEvent=o,exports.isExecuteBashObservationEvent=s,exports.isFullStateConversationStateUpdateEvent=h,exports.isHookExecutionEvent=x,exports.isMessageEvent=r,exports.isObservationEvent=t,exports.isPlanningFileEditorObservationEvent=c,exports.isStatsConversationStateUpdateEvent=_,exports.isStreamingDeltaEvent=C,exports.isSwitchLLMObservationEvent=u,exports.isSystemPromptEvent=p,exports.isUserMessageEvent=i;
2
2
  //# sourceMappingURL=type-guards.cjs.map