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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (600) hide show
  1. package/README.md +46 -31
  2. package/README.windows.md +2 -2
  3. package/bin/agent-canvas.mjs +3 -1
  4. package/build/assets/Trans-CBypf0vt.js +1 -0
  5. package/build/assets/{acp-providers-BqUvf67Q.js → acp-providers-BMyF5WII.js} +1 -1
  6. package/build/assets/active-backend-context-Cy_Ui5d7.js +1 -0
  7. package/build/assets/add-backend-modal-CUw7x0zm.js +1 -0
  8. package/build/assets/agent-server-client-options-FoO1qgAQ.js +1 -0
  9. package/build/assets/agent-server-conversation-service.api-D6Cmbnhd.js +5 -0
  10. package/build/assets/{agent-settings-DoHXHcoA.js → agent-settings-DW4vwOaz.js} +2 -2
  11. package/build/assets/{alert-banner-Bsvys-hT.js → alert-banner-BHmoArV2.js} +1 -1
  12. package/build/assets/{analytics-consent-form-modal-CVhsAREx.js → analytics-consent-form-modal-BNK0yu4L.js} +1 -1
  13. package/build/assets/api-key-entry-screen-BjVajIjf.js +1 -0
  14. package/build/assets/app-settings-C-5X6RzZ.js +1 -0
  15. package/build/assets/automation-detail-uDMoYmAc.js +1 -0
  16. package/build/assets/automations-list-DBCKCbId.js +1 -0
  17. package/build/assets/{back-nav-button-D20Avel_.js → back-nav-button-Bckz5Wh6.js} +1 -1
  18. package/build/assets/backend-form-modal-D2-XqJA4.js +1 -0
  19. package/build/assets/{backend-synced-settings-badge-Dcd4712m.js → backend-synced-settings-badge-Dx16CR_k.js} +1 -1
  20. package/build/assets/{base-modal-DvuGYyu1.js → base-modal-7QRNzf6r.js} +1 -1
  21. package/build/assets/{brand-button-9SOzmqPP.js → brand-button-CKLvirxz.js} +1 -1
  22. package/build/assets/browser-D1ZybR7v.js +5 -0
  23. package/build/assets/browser-store-hzasvz9c.js +1 -0
  24. package/build/assets/{browser-tab-bveyJhG9.js → browser-tab-iOQjXzmI.js} +1 -1
  25. package/build/assets/chat-send-button-_Uc9iFpG.js +1 -0
  26. package/build/assets/check-DfvhVBub.js +1 -0
  27. package/build/assets/{checkmark--JWAesua.js → checkmark-BHPhb50L.js} +1 -1
  28. package/build/assets/{chevron-down-B9j6lcFg.js → chevron-down-CMkqyPEY.js} +1 -1
  29. package/build/assets/{circle-plus-check-toggle-AO9DWyDX.js → circle-plus-check-toggle-ChmnRlpR.js} +1 -1
  30. package/build/assets/{close--W-tHn1h.js → close-DBs90sI6.js} +1 -1
  31. package/build/assets/{code-tag-chmctf4w.js → code-tag-BtHOqHwB.js} +1 -1
  32. package/build/assets/{color-themes-0biOprdo.js → color-themes-CBikRn3w.js} +1 -1
  33. package/build/assets/{combobox-caret-C9BNHfSu.js → combobox-caret-evUAh6YW.js} +1 -1
  34. package/build/assets/{command-store-UzKGSUC2.js → command-store-DZfR8QtE.js} +1 -1
  35. package/build/assets/condenser-settings-0tw3yXX8.js +1 -0
  36. package/build/assets/{confirmation-modal-Cq3eqvqH.js → confirmation-modal-DWuxe1zG.js} +1 -1
  37. package/build/assets/{context-menu-list-item-BQU0jZPq.js → context-menu-list-item-BbHFxHaq.js} +1 -1
  38. package/build/assets/conversation-B1v96pQf.js +19 -0
  39. package/build/assets/conversation-DgfcjCPm.js +1 -0
  40. package/build/assets/{conversation-local-storage-an3MiIiJ.js → conversation-local-storage-Btum2xBJ.js} +1 -1
  41. package/build/assets/conversation-panel-TJ7swm6a.js +1 -0
  42. package/build/assets/conversation-service.api-DXawvmNN.js +1 -0
  43. package/build/assets/conversation-state-store-DmuPn875.js +1 -0
  44. package/build/assets/{conversation-store-FQmakEd-.js → conversation-store-Bu89Yxg1.js} +1 -1
  45. package/build/assets/{conversation-tab-empty-state-C8tztloo.js → conversation-tab-empty-state-7js7FjYM.js} +1 -1
  46. package/build/assets/{copy-CdKN5rtJ.js → copy-B0SkXenR.js} +1 -1
  47. package/build/assets/copy-to-clipboard-button-CfH2EQz9.js +1 -0
  48. package/build/assets/{createLucideIcon-CkGTf9Qj.js → createLucideIcon-Bazr-V-B.js} +1 -1
  49. package/build/assets/declaration-Cn-NXHEy.js +1 -0
  50. package/build/assets/{device-verify-YuGXnpRk.js → device-verify-CWKyQ680.js} +1 -1
  51. package/build/assets/{dist-5dObF4p4.js → dist-Cbu6eGx8.js} +1 -1
  52. package/build/assets/dist-Dg2JWLGc.js +1 -0
  53. package/build/assets/{dropdown-classes-CVp0kVdt.js → dropdown-classes-BI1bI1ho.js} +1 -1
  54. package/build/assets/edit-automation-modal-DdAG6kFZ.js +1 -0
  55. package/build/assets/{ellipsis-button-k7HLwYth.js → ellipsis-button-DdCsOBHV.js} +1 -1
  56. package/build/assets/entry.client-DXyvKj5G.js +2 -0
  57. package/build/assets/{enum-filter-dropdown-COqUq3mB.js → enum-filter-dropdown-WROAIeys.js} +1 -1
  58. package/build/assets/{environment-switch-overlay-wB5LxfYZ.js → environment-switch-overlay-Dv0imPE6.js} +1 -1
  59. package/build/assets/{extensions-hub-CoWO3SzQ.js → extensions-hub-CkyDPXvn.js} +1 -1
  60. package/build/assets/{extensions-navigation-D5w2sFQe.js → extensions-navigation-gMR-la1J.js} +1 -1
  61. package/build/assets/{external-link-BATfjnkz.js → external-link-FsutnU75.js} +1 -1
  62. package/build/assets/files-tab-DNUoveJZ.js +1 -0
  63. package/build/assets/files-tab-store-SyvkH3ic.js +1 -0
  64. package/build/assets/{folder-DPTBlxWb.js → folder-DusyBXDE.js} +1 -1
  65. package/build/assets/{globe-Dpgjreyy.js → globe-BUcin4kT.js} +1 -1
  66. package/build/assets/home-D809jWVS.js +1 -0
  67. package/build/assets/{iconBase-BVhFI-0E.js → iconBase-B6CXDDaE.js} +1 -1
  68. package/build/assets/index-redirect-nMYgOTBX.js +1 -0
  69. package/build/assets/install-server-modal-D92Qy57I.js +1 -0
  70. package/build/assets/{launch-fU77utLO.js → launch-BnCG2g2a.js} +1 -1
  71. package/build/assets/lesson-plan-j-ZaE8vK.js +3 -0
  72. package/build/assets/{lightbulb-S616sGEL.js → lightbulb-BJ5tWmAh.js} +1 -1
  73. package/build/assets/{link-external-ooNztGLp.js → link-external-DUtmHAHi.js} +1 -1
  74. package/build/assets/{list-todo-nCa9zxVE.js → list-todo-C-gekh-4.js} +1 -1
  75. package/build/assets/{llm-client-P9f2gKeW.js → llm-client-BZUkZYlc.js} +1 -1
  76. package/build/assets/llm-not-configured-banner-PlvJ99rE.js +27 -0
  77. package/build/assets/llm-settings-Dgk32xRW.js +1 -0
  78. package/build/assets/llm-settings-Dxo7owKm.js +1 -0
  79. package/build/assets/llm-subscription-Bvu8BLXc.js +1 -0
  80. package/build/assets/llm-subscription-service-Bq6z3Wkv.js +1 -0
  81. package/build/assets/loader-circle-Cw7_q9hg.js +1 -0
  82. package/build/assets/{loading-spinner-D7bOU6I7.js → loading-spinner-RF3IlMF5.js} +1 -1
  83. package/build/assets/manage-backends-modal-BT66a6e0.js +1 -0
  84. package/build/assets/manifest-b8402d59.js +1 -0
  85. package/build/assets/markdown-renderer-Tw6FR2ad.js +2 -0
  86. package/build/assets/mcp-B_pA7vZg.js +9 -0
  87. package/build/assets/mcp-client-ppbYplKX.js +1 -0
  88. package/build/assets/messages-Cg9aNVi6.js +41 -0
  89. package/build/assets/{modal-backdrop-_VbcKk5K.js → modal-backdrop-DRpBVVW5.js} +1 -1
  90. package/build/assets/{modal-body-Cd-PtMHr.js → modal-body-CEV2O67p.js} +1 -1
  91. package/build/assets/{modal-classes-CNm4ovfm.js → modal-classes-B2DuQ9qD.js} +1 -1
  92. package/build/assets/{modal-close-button-Dbo0NAMt.js → modal-close-button-gtb7RHFB.js} +1 -1
  93. package/build/assets/model-selector-CAv3RrJ3.js +1 -0
  94. package/build/assets/{mouse-pointer-click-D0QNGSIo.js → mouse-pointer-click-B3i6HcaF.js} +1 -1
  95. package/build/assets/{navigation-context-BpAOh_t5.js → navigation-context-CM9JmTvm.js} +1 -1
  96. package/build/assets/{navigation-link-Dci7Nuyf.js → navigation-link-FmXzqR1J.js} +1 -1
  97. package/build/assets/onboarding-Q9CzuVWy.js +1 -0
  98. package/build/assets/{openhands-logo-Dzm-d_V_.js → openhands-logo-B4aEO2sf.js} +1 -1
  99. package/build/assets/option-service.api-C-s2BYZp.js +1 -0
  100. package/build/assets/organization-service.api-CXTKpFnV.js +1 -0
  101. package/build/assets/{path-utils-YlkpoImJ.js → path-utils-CE98fIFP.js} +1 -1
  102. package/build/assets/{pencil-DPEtl5QD.js → pencil-bWrxRWlr.js} +1 -1
  103. package/build/assets/{plan-components-CutRBi0G.js → plan-components-BF-X7vnQ.js} +1 -1
  104. package/build/assets/{planner-tab-DjIFIQDk.js → planner-tab-jkyaGiRc.js} +1 -1
  105. package/build/assets/plus-BTCK8WtR.js +1 -0
  106. package/build/assets/{profiles-client-BNvHck-I.js → profiles-client-CQ9L1yHR.js} +1 -1
  107. package/build/assets/providers-B3hkV58J.js +1 -0
  108. package/build/assets/proxy-BOcEWkCD.js +1 -0
  109. package/build/assets/{react-dom-hVBnwgwZ.js → react-dom-BBXlXOZX.js} +1 -1
  110. package/build/assets/{react-CM_dJw1Z.js → react-uQK8du1l.js} +1 -1
  111. package/build/assets/{react-Dy05vyj5.js → react-x84lbX6s.js} +1 -1
  112. package/build/assets/{recommended-automations-launcher-DCi0RXIj.js → recommended-automations-launcher-DMk35aFI.js} +11 -11
  113. package/build/assets/root-CV0kyxfP.js +2 -0
  114. package/build/assets/root-PB2Jnj61.css +1 -0
  115. package/build/assets/root-layout-Bl4Qzg5J.js +2 -0
  116. package/build/assets/{runtime-waiting-state-8i0Z3A_i.js → runtime-waiting-state-C1hJpXxl.js} +1 -1
  117. package/build/assets/sdk-section-page-DHbC2_j3.js +1 -0
  118. package/build/assets/sdk-settings-schema-z51bBmMl.js +1 -0
  119. package/build/assets/{search-C_l_XW4e.js → search-Dxm1MUMi.js} +1 -1
  120. package/build/assets/{secrets-service-D6Gcymcs.js → secrets-service-DlScPUwy.js} +1 -1
  121. package/build/assets/secrets-settings-B97-JKBe.js +1 -0
  122. package/build/assets/settings-BpmooyBV.js +1 -0
  123. package/build/assets/{settings-dropdown-input-BP-arqjU.js → settings-dropdown-input-hIIAlmHb.js} +1 -1
  124. package/build/assets/{settings-gear-f-zWpxfI.js → settings-gear-DQLTCnFx.js} +1 -1
  125. package/build/assets/{settings-index-B035V2pu.js → settings-index-kKASonWk.js} +1 -1
  126. package/build/assets/{settings-input-BM8ANxDb.js → settings-input-BlOzCtP3.js} +1 -1
  127. package/build/assets/{settings-list-classes-B9uo5WES.js → settings-list-classes-BFRbCy4U.js} +1 -1
  128. package/build/assets/settings-modal-C4pZwj-l.js +1 -0
  129. package/build/assets/{settings-section-header-context-Cid25HM2.js → settings-section-header-context-iz4Go0dL.js} +1 -1
  130. package/build/assets/settings-service.api-DVLwi82B.js +1 -0
  131. package/build/assets/{settings-switch-xa6q4M6j.js → settings-switch-6cXIH-UE.js} +1 -1
  132. package/build/assets/{settings-utils--H_EvFjx.js → settings-utils-CfScEaPn.js} +1 -1
  133. package/build/assets/shared-conversation-CLkayApe.js +1 -0
  134. package/build/assets/sidebar-mobile-menu-toggle-C8uT4Mhd.js +1 -0
  135. package/build/assets/{sidebar-nav-link-CPWuQ_c6.js → sidebar-nav-link-BKZiAQxQ.js} +1 -1
  136. package/build/assets/{skill-card-pill-row-DeodrwPG.js → skill-card-pill-row-D13WRKIE.js} +1 -1
  137. package/build/assets/{skills-BE5HJuGM.js → skills-NpRk6v79.js} +1 -1
  138. package/build/assets/{skills-client-Ui_9FvXp.js → skills-client-DsqwQEwj.js} +1 -1
  139. package/build/assets/{skills-plugins-Dc4ec3CW.js → skills-plugins-bkwxItAw.js} +1 -1
  140. package/build/assets/{skills-settings-B6HwvA0S.js → skills-settings-DMbrlB2b.js} +2 -2
  141. package/build/assets/{square-chevron-right-BWAB7NPp.js → square-chevron-right-DxZKcVq4.js} +1 -1
  142. package/build/assets/{styled-tooltip-X61SEwqk.js → styled-tooltip-DG1ofAcS.js} +1 -1
  143. package/build/assets/suspense-sOGeme-f.js +1 -0
  144. package/build/assets/{switch-skeleton-BbIWemkK.js → switch-skeleton-CZ6XCVZk.js} +1 -1
  145. package/build/assets/{task-list-tab-BFnyHGsn.js → task-list-tab-CddMPNCD.js} +1 -1
  146. package/build/assets/telemetry-CX4mTZUw.js +2 -0
  147. package/build/assets/{terminal-CltMeLv4.js → terminal-BOAVxAej.js} +1 -1
  148. package/build/assets/{terminal-B92mACR5.js → terminal-DbtwHqt4.js} +1 -1
  149. package/build/assets/{toggle-switch-CL_wRiGs.js → toggle-switch-C0t6ge2m.js} +1 -1
  150. package/build/assets/{trash-2-C-RvV8WA.js → trash-2-Dmprz0A0.js} +1 -1
  151. package/build/assets/{typography-BLSEGjph.js → typography-CNHbO1eE.js} +1 -1
  152. package/build/assets/{u-check-circle-dG_VJqx5.js → u-check-circle-CX66WzfT.js} +1 -1
  153. package/build/assets/{u-check-circle-half-D-5ZPRnd.js → u-check-circle-half-Bj853Ub0.js} +1 -1
  154. package/build/assets/{u-circuit-BXoisXOA.js → u-circuit-B9bLCP7N.js} +1 -1
  155. package/build/assets/{u-edit-DIgADxLH.js → u-edit-D7JyvoWm.js} +1 -1
  156. package/build/assets/use-acp-credential-form-Cj_oUYd5.js +1 -0
  157. package/build/assets/{use-active-conversation-B0_rXnqa.js → use-active-conversation-B64-yy2X.js} +1 -1
  158. package/build/assets/use-agent-settings-schema-BzbQYEzb.js +1 -0
  159. package/build/assets/{use-agent-state-BuOzLeFN.js → use-agent-state-DxFk391r.js} +1 -1
  160. package/build/assets/{use-breakpoint-DpxHDmuH.js → use-breakpoint-Cent5lpI.js} +1 -1
  161. package/build/assets/{use-click-outside-element-DhxCUyWl.js → use-click-outside-element-DOYR26nw.js} +1 -1
  162. package/build/assets/{use-cloud-current-user-id-DVZXa_WH.js → use-cloud-current-user-id-BVf7pb8n.js} +1 -1
  163. package/build/assets/use-config-CvdJUq4E.js +1 -0
  164. package/build/assets/use-create-conversation-Cnouynop.js +1 -0
  165. package/build/assets/{use-create-secret-ClPpLBgD.js → use-create-secret-Cgu4uxyr.js} +1 -1
  166. package/build/assets/{use-event-store-DNSmyzUh.js → use-event-store-Nv92IYMU.js} +1 -1
  167. package/build/assets/use-handle-plan-click-C7824bbe.js +1 -0
  168. package/build/assets/use-is-authed-mnJtd2bw.js +1 -0
  169. package/build/assets/{use-launch-skill-in-chat-BTgXIu3N.js → use-launch-skill-in-chat-NDUo_UCA.js} +1 -1
  170. package/build/assets/use-llm-profiles-9eH3Y3Ef.js +1 -0
  171. package/build/assets/use-runtime-is-ready-DEnxJH7W.js +1 -0
  172. package/build/assets/use-save-settings-DrClHnX7.js +1 -0
  173. package/build/assets/use-settings-BNAoCX93.js +1 -0
  174. package/build/assets/{use-settings-nav-items-DVrMNk0I.js → use-settings-nav-items-CLIW2p2n.js} +2 -2
  175. package/build/assets/{use-skills-Bv8LXrys.js → use-skills-B9gOHrOj.js} +1 -1
  176. package/build/assets/{use-task-list-E5t-jtgs.js → use-task-list-DLKPnq3I.js} +1 -1
  177. package/build/assets/{use-tracking-BhyV5A9i.js → use-tracking-Dph_dRlL.js} +1 -1
  178. package/build/assets/{use-user-conversation-6yFVEXiG.js → use-user-conversation-leIsQH1B.js} +1 -1
  179. package/build/assets/useMutation-cXADjWAv.js +1 -0
  180. package/build/assets/useQuery-BQr6A6ry.js +1 -0
  181. package/build/assets/useTranslation-Bp1btAjp.js +1 -0
  182. package/build/assets/{utils-eXk6yerZ.js → utils-o-OXNtEy.js} +1 -1
  183. package/build/assets/v4-DOSjXdIn.js +1 -0
  184. package/build/assets/{vendor~browser-tab-BGJDGHyS.js → vendor~browser-tab-642bOcE1.js} +1 -1
  185. package/build/assets/{vendor~conversation-panel~conversation-D98u43rl.js → vendor~conversation-panel~conversation-DqmbnXRn.js} +1 -1
  186. package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CtjHOMO_.js → vendor~conversation-panel~conversation~alert-banner-CSDVP1nw.js} +1 -1
  187. package/build/assets/{vendor~conversation-panel~conversation~index-BXt2-3Cc.js → vendor~conversation-panel~conversation~index-DITarr3F.js} +1 -1
  188. package/build/assets/{vendor~entry.client-DrAdOKqA.js → vendor~entry.client-CQ77DucR.js} +1 -1
  189. package/build/assets/{vendor~entry.client-EcEhmoJW.js → vendor~entry.client-ePAFmSwg.js} +1 -1
  190. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~f0pn7nss-DUk-MwlC.js +177 -0
  191. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~lb3qbbk3-BvmOva8I.js +1 -0
  192. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-Cl4h-NSi.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BkQQxq_q.js} +1 -1
  193. package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BmOMM-6e.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-8xF3WeB9.js} +1 -1
  194. package/build/assets/{vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~cnj3raoq-BjMt2JeR.js → vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~nyk4vv4g-UzR6fe3Y.js} +1 -1
  195. package/build/assets/{vendor~files-tab--640YzQO.js → vendor~files-tab-Cko7Kr5k.js} +1 -1
  196. package/build/assets/{vendor~home~conversation-panel~conversation-dhKA2JVJ.js → vendor~home~conversation-panel~conversation-D3otw5Jn.js} +1 -1
  197. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DMOoHVBy.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CMdKUYP2.js} +1 -1
  198. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BoE6JRJj.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DSR6Mugx.js} +1 -1
  199. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dqpi2xyZ.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DdOzMvB1.js} +1 -1
  200. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DX2CmDJ0.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dj2eezvL.js} +1 -1
  201. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BNExlCqT.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DyN8jeZz.js} +1 -1
  202. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DCn1M97v.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-lpEWrbMA.js} +1 -1
  203. package/build/assets/{vendor~launch-C0VvUe2W.js → vendor~launch-DoYO54df.js} +1 -1
  204. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-COLUW-6M.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-BGwU2SbU.js} +1 -1
  205. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-eG1kjEbj.js → vendor~root-layout~home~conversation-panel~conversation-Iqs0j4Wo.js} +1 -1
  206. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-7eqKdLSQ.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BdS6bbw9.js} +1 -1
  207. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BP3MGAAY.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-Fd3F3jth.js} +1 -1
  208. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Dkd2wxJA.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Cg0AqwMN.js} +2 -2
  209. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-_LydBB1e.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-BlsbqRyZ.js} +1 -1
  210. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~ec6pk3ix-CBICqfKC.js +48 -0
  211. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~mcp~automati~dou5smdo-DavKsAvB.js → vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~nv6afr11-BYNoKMU0.js} +97 -69
  212. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CsO1gYxF.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BspUuSsP.js} +1 -1
  213. package/build/assets/{vendor~root-layout~home~mcp~automations-list-D40jgugf.js → vendor~root-layout~home~mcp~automations-list-C9U_eOqU.js} +1 -1
  214. package/build/assets/{vendor~root-layout~home~mcp~automations-list-cNHi83v_.js → vendor~root-layout~home~mcp~automations-list-DhQ3LPVw.js} +1 -1
  215. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-xCM3k6Rd.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BEbhHQYg.js} +1 -1
  216. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BIm99UaF.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-DdgDNzMc.js} +2 -2
  217. package/build/assets/{verification-settings-Be6NxjuT.js → verification-settings-D7R-Ne6L.js} +1 -1
  218. package/build/assets/x-DCZg87p7.js +1 -0
  219. package/build/assets/{x-mark-C42svtnu.js → x-mark-jrBTJbnP.js} +1 -1
  220. package/build/index.html +4 -4
  221. package/build/locales/ar/openhands.json +22 -0
  222. package/build/locales/ca/openhands.json +22 -0
  223. package/build/locales/de/openhands.json +22 -0
  224. package/build/locales/en/openhands.json +22 -0
  225. package/build/locales/es/openhands.json +22 -0
  226. package/build/locales/fr/openhands.json +22 -0
  227. package/build/locales/it/openhands.json +22 -0
  228. package/build/locales/ja/openhands.json +22 -0
  229. package/build/locales/ko-KR/openhands.json +22 -0
  230. package/build/locales/no/openhands.json +22 -0
  231. package/build/locales/pt/openhands.json +22 -0
  232. package/build/locales/tr/openhands.json +22 -0
  233. package/build/locales/uk/openhands.json +22 -0
  234. package/build/locales/zh-CN/openhands.json +22 -0
  235. package/build/locales/zh-TW/openhands.json +22 -0
  236. package/config/defaults.json +4 -7
  237. package/dist/api/agent-server-adapter.cjs +3 -3
  238. package/dist/api/agent-server-adapter.cjs.map +1 -1
  239. package/dist/api/agent-server-adapter.d.ts +8 -0
  240. package/dist/api/agent-server-adapter.js +82 -80
  241. package/dist/api/agent-server-adapter.js.map +1 -1
  242. package/dist/api/agent-server-compatibility.cjs +1 -1
  243. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  244. package/dist/api/agent-server-compatibility.d.ts +10 -0
  245. package/dist/api/agent-server-compatibility.js +69 -25
  246. package/dist/api/agent-server-compatibility.js.map +1 -1
  247. package/dist/api/backend-registry/default-backend.cjs +1 -1
  248. package/dist/api/backend-registry/default-backend.cjs.map +1 -1
  249. package/dist/api/backend-registry/default-backend.d.ts +6 -5
  250. package/dist/api/backend-registry/default-backend.js +1 -1
  251. package/dist/api/backend-registry/default-backend.js.map +1 -1
  252. package/dist/api/backend-registry/storage.cjs +1 -1
  253. package/dist/api/backend-registry/storage.cjs.map +1 -1
  254. package/dist/api/backend-registry/storage.js +38 -68
  255. package/dist/api/backend-registry/storage.js.map +1 -1
  256. package/dist/api/cloud/proxy.cjs +1 -1
  257. package/dist/api/cloud/proxy.cjs.map +1 -1
  258. package/dist/api/cloud/proxy.d.ts +3 -16
  259. package/dist/api/cloud/proxy.js +1 -1
  260. package/dist/api/cloud/proxy.js.map +1 -1
  261. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  262. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  263. package/dist/api/conversation-service/agent-server-conversation-service.api.js +75 -75
  264. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  265. package/dist/api/llm-subscription-service.cjs +2 -0
  266. package/dist/api/llm-subscription-service.cjs.map +1 -0
  267. package/dist/api/llm-subscription-service.d.ts +23 -0
  268. package/dist/api/llm-subscription-service.js +109 -0
  269. package/dist/api/llm-subscription-service.js.map +1 -0
  270. package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
  271. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
  272. package/dist/api/mcp-service/mcp-service.api.d.ts +2 -3
  273. package/dist/api/mcp-service/mcp-service.api.js +38 -13
  274. package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
  275. package/dist/api/settings-service/settings-service.api.cjs +1 -1
  276. package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
  277. package/dist/api/settings-service/settings-service.api.js +41 -42
  278. package/dist/api/settings-service/settings-service.api.js.map +1 -1
  279. package/dist/components/conversation-events/chat/messages.cjs +1 -1
  280. package/dist/components/conversation-events/chat/messages.cjs.map +1 -1
  281. package/dist/components/conversation-events/chat/messages.js +4 -4
  282. package/dist/components/conversation-events/chat/messages.js.map +1 -1
  283. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  284. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  285. package/dist/components/features/backends/backend-form-modal.js +136 -135
  286. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  287. package/dist/components/features/backends/backend-selector.cjs +1 -1
  288. package/dist/components/features/backends/backend-selector.cjs.map +1 -1
  289. package/dist/components/features/backends/backend-selector.js +103 -91
  290. package/dist/components/features/backends/backend-selector.js.map +1 -1
  291. package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
  292. package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
  293. package/dist/components/features/backends/manage-backends-modal.js +14 -8
  294. package/dist/components/features/backends/manage-backends-modal.js.map +1 -1
  295. package/dist/components/features/chat/path-component.cjs +1 -1
  296. package/dist/components/features/chat/path-component.cjs.map +1 -1
  297. package/dist/components/features/chat/path-component.js +1 -1
  298. package/dist/components/features/chat/path-component.js.map +1 -1
  299. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs +1 -1
  300. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs.map +1 -1
  301. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js +77 -66
  302. package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js.map +1 -1
  303. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  304. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  305. package/dist/components/features/mcp-page/custom-server-editor.js +1 -0
  306. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  307. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  308. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  309. package/dist/components/features/mcp-page/install-server-modal.js +73 -46
  310. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  311. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  312. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  313. package/dist/components/features/mcp-page/marketplace-card.js +6 -2
  314. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  315. package/dist/components/features/settings/brand-button.cjs +1 -1
  316. package/dist/components/features/settings/brand-button.cjs.map +1 -1
  317. package/dist/components/features/settings/brand-button.js +1 -1
  318. package/dist/components/features/settings/brand-button.js.map +1 -1
  319. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs +2 -0
  320. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs.map +1 -0
  321. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.d.ts +5 -0
  322. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js +167 -0
  323. package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js.map +1 -0
  324. package/dist/components/shared/modals/settings/model-selector.cjs +1 -1
  325. package/dist/components/shared/modals/settings/model-selector.cjs.map +1 -1
  326. package/dist/components/shared/modals/settings/model-selector.d.ts +1 -2
  327. package/dist/components/shared/modals/settings/model-selector.js +59 -65
  328. package/dist/components/shared/modals/settings/model-selector.js.map +1 -1
  329. package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
  330. package/dist/components/shared/modals/settings/settings-form.cjs.map +1 -1
  331. package/dist/components/shared/modals/settings/settings-form.js +1 -2
  332. package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
  333. package/dist/config/defaults.cjs +2 -0
  334. package/dist/config/defaults.cjs.map +1 -0
  335. package/dist/config/defaults.js +35 -0
  336. package/dist/config/defaults.js.map +1 -0
  337. package/dist/constants/llm-subscription.cjs +2 -0
  338. package/dist/constants/llm-subscription.cjs.map +1 -0
  339. package/dist/constants/llm-subscription.d.ts +16 -0
  340. package/dist/constants/llm-subscription.js +47 -0
  341. package/dist/constants/llm-subscription.js.map +1 -0
  342. package/dist/contexts/conversation-websocket-context.cjs +1 -1
  343. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  344. package/dist/contexts/conversation-websocket-context.js +1 -1
  345. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  346. package/dist/hooks/mutation/use-llm-subscription-auth.cjs +2 -0
  347. package/dist/hooks/mutation/use-llm-subscription-auth.cjs.map +1 -0
  348. package/dist/hooks/mutation/use-llm-subscription-auth.d.ts +3 -0
  349. package/dist/hooks/mutation/use-llm-subscription-auth.js +30 -0
  350. package/dist/hooks/mutation/use-llm-subscription-auth.js.map +1 -0
  351. package/dist/hooks/mutation/use-save-fields-as-secrets.cjs +1 -1
  352. package/dist/hooks/mutation/use-save-fields-as-secrets.cjs.map +1 -1
  353. package/dist/hooks/mutation/use-save-fields-as-secrets.d.ts +8 -6
  354. package/dist/hooks/mutation/use-save-fields-as-secrets.js +1 -1
  355. package/dist/hooks/mutation/use-save-fields-as-secrets.js.map +1 -1
  356. package/dist/hooks/mutation/use-test-mcp-server.d.ts +1 -1
  357. package/dist/hooks/query/query-keys.cjs +1 -1
  358. package/dist/hooks/query/query-keys.cjs.map +1 -1
  359. package/dist/hooks/query/query-keys.d.ts +5 -0
  360. package/dist/hooks/query/query-keys.js +14 -2
  361. package/dist/hooks/query/query-keys.js.map +1 -1
  362. package/dist/hooks/query/use-agent-settings-schema.cjs +1 -1
  363. package/dist/hooks/query/use-agent-settings-schema.cjs.map +1 -1
  364. package/dist/hooks/query/use-agent-settings-schema.d.ts +2 -2
  365. package/dist/hooks/query/use-agent-settings-schema.js +21 -19
  366. package/dist/hooks/query/use-agent-settings-schema.js.map +1 -1
  367. package/dist/hooks/query/use-backends-health.cjs +1 -1
  368. package/dist/hooks/query/use-backends-health.cjs.map +1 -1
  369. package/dist/hooks/query/use-backends-health.js +38 -36
  370. package/dist/hooks/query/use-backends-health.js.map +1 -1
  371. package/dist/hooks/query/use-llm-subscription-models.cjs +2 -0
  372. package/dist/hooks/query/use-llm-subscription-models.cjs.map +1 -0
  373. package/dist/hooks/query/use-llm-subscription-models.d.ts +3 -0
  374. package/dist/hooks/query/use-llm-subscription-models.js +19 -0
  375. package/dist/hooks/query/use-llm-subscription-models.js.map +1 -0
  376. package/dist/hooks/query/use-llm-subscription-status.cjs +2 -0
  377. package/dist/hooks/query/use-llm-subscription-status.cjs.map +1 -0
  378. package/dist/hooks/query/use-llm-subscription-status.d.ts +3 -0
  379. package/dist/hooks/query/use-llm-subscription-status.js +19 -0
  380. package/dist/hooks/query/use-llm-subscription-status.js.map +1 -0
  381. package/dist/hooks/use-websocket.cjs +1 -1
  382. package/dist/hooks/use-websocket.cjs.map +1 -1
  383. package/dist/hooks/use-websocket.d.ts +0 -1
  384. package/dist/hooks/use-websocket.js +37 -38
  385. package/dist/hooks/use-websocket.js.map +1 -1
  386. package/dist/i18n/declaration.cjs +1 -1
  387. package/dist/i18n/declaration.cjs.map +1 -1
  388. package/dist/i18n/declaration.d.ts +22 -0
  389. package/dist/i18n/declaration.js +1 -1
  390. package/dist/i18n/declaration.js.map +1 -1
  391. package/dist/i18n/translation.cjs +2 -2
  392. package/dist/i18n/translation.cjs.map +1 -1
  393. package/dist/i18n/translation.js +374 -0
  394. package/dist/i18n/translation.js.map +1 -1
  395. package/dist/locales/ar/openhands.json +22 -0
  396. package/dist/locales/ca/openhands.json +22 -0
  397. package/dist/locales/de/openhands.json +22 -0
  398. package/dist/locales/en/openhands.json +22 -0
  399. package/dist/locales/es/openhands.json +22 -0
  400. package/dist/locales/fr/openhands.json +22 -0
  401. package/dist/locales/it/openhands.json +22 -0
  402. package/dist/locales/ja/openhands.json +22 -0
  403. package/dist/locales/ko-KR/openhands.json +22 -0
  404. package/dist/locales/no/openhands.json +22 -0
  405. package/dist/locales/pt/openhands.json +22 -0
  406. package/dist/locales/tr/openhands.json +22 -0
  407. package/dist/locales/uk/openhands.json +22 -0
  408. package/dist/locales/zh-CN/openhands.json +22 -0
  409. package/dist/locales/zh-TW/openhands.json +22 -0
  410. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +1 -1
  411. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -1
  412. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +10 -22
  413. package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
  414. package/dist/node_modules/@openhands/extensions/skills/index.cjs +97 -69
  415. package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
  416. package/dist/node_modules/@openhands/extensions/skills/index.js +3 -3
  417. package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
  418. package/dist/package.cjs +1 -1
  419. package/dist/package.cjs.map +1 -1
  420. package/dist/package.js +3 -5
  421. package/dist/package.js.map +1 -1
  422. package/dist/routes/files-tab.cjs +1 -1
  423. package/dist/routes/files-tab.cjs.map +1 -1
  424. package/dist/routes/files-tab.js +28 -17
  425. package/dist/routes/files-tab.js.map +1 -1
  426. package/dist/routes/llm-settings.cjs +1 -1
  427. package/dist/routes/llm-settings.cjs.map +1 -1
  428. package/dist/routes/llm-settings.js +142 -85
  429. package/dist/routes/llm-settings.js.map +1 -1
  430. package/dist/services/canvas-ui.cjs +1 -1
  431. package/dist/services/canvas-ui.cjs.map +1 -1
  432. package/dist/services/canvas-ui.d.ts +1 -1
  433. package/dist/services/canvas-ui.js +2 -2
  434. package/dist/services/canvas-ui.js.map +1 -1
  435. package/dist/stores/files-tab-store.cjs +1 -1
  436. package/dist/stores/files-tab-store.cjs.map +1 -1
  437. package/dist/stores/files-tab-store.d.ts +2 -1
  438. package/dist/stores/files-tab-store.js +5 -1
  439. package/dist/stores/files-tab-store.js.map +1 -1
  440. package/dist/stores/use-event-store.cjs +1 -1
  441. package/dist/stores/use-event-store.cjs.map +1 -1
  442. package/dist/stores/use-event-store.js +39 -34
  443. package/dist/stores/use-event-store.js.map +1 -1
  444. package/dist/types/mcp-server.d.ts +21 -0
  445. package/dist/ui/dropdown/dropdown.cjs +1 -1
  446. package/dist/ui/dropdown/dropdown.cjs.map +1 -1
  447. package/dist/ui/dropdown/dropdown.js +6 -2
  448. package/dist/ui/dropdown/dropdown.js.map +1 -1
  449. package/dist/utils/handle-event-for-ui.cjs +1 -1
  450. package/dist/utils/handle-event-for-ui.cjs.map +1 -1
  451. package/dist/utils/handle-event-for-ui.d.ts +2 -0
  452. package/dist/utils/handle-event-for-ui.js +1 -1
  453. package/dist/utils/handle-event-for-ui.js.map +1 -1
  454. package/dist/utils/llm-subscription-schema.cjs +2 -0
  455. package/dist/utils/llm-subscription-schema.cjs.map +1 -0
  456. package/dist/utils/llm-subscription-schema.d.ts +2 -0
  457. package/dist/utils/llm-subscription-schema.js +22 -0
  458. package/dist/utils/llm-subscription-schema.js.map +1 -0
  459. package/dist/utils/mcp-config.cjs +1 -1
  460. package/dist/utils/mcp-config.cjs.map +1 -1
  461. package/dist/utils/mcp-config.js +32 -17
  462. package/dist/utils/mcp-config.js.map +1 -1
  463. package/dist/utils/mcp-credential-validation.cjs +2 -0
  464. package/dist/utils/mcp-credential-validation.cjs.map +1 -0
  465. package/dist/utils/mcp-credential-validation.d.ts +22 -0
  466. package/dist/utils/mcp-credential-validation.js +31 -0
  467. package/dist/utils/mcp-credential-validation.js.map +1 -0
  468. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  469. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  470. package/dist/utils/mcp-marketplace-utils.d.ts +7 -2
  471. package/dist/utils/mcp-marketplace-utils.js +33 -48
  472. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  473. package/dist/utils/sdk-settings-schema.cjs +1 -1
  474. package/dist/utils/sdk-settings-schema.cjs.map +1 -1
  475. package/dist/utils/sdk-settings-schema.js +64 -61
  476. package/dist/utils/sdk-settings-schema.js.map +1 -1
  477. package/dist/utils/websocket-url.cjs +1 -1
  478. package/dist/utils/websocket-url.cjs.map +1 -1
  479. package/dist/utils/websocket-url.js +2 -2
  480. package/dist/utils/websocket-url.js.map +1 -1
  481. package/package.json +3 -5
  482. package/scripts/check-sdk-version-sync.mjs +9 -27
  483. package/scripts/dev-with-automation.mjs +1 -3
  484. package/scripts/docker-build.mjs +0 -4
  485. package/scripts/run-staged-typecheck.mjs +44 -0
  486. package/build/assets/QueryClientProvider-XcSjsfpb.js +0 -1
  487. package/build/assets/Trans-sy4l4TyQ.js +0 -1
  488. package/build/assets/active-backend-context-CNF2lPkA.js +0 -1
  489. package/build/assets/add-backend-modal-BywVr6uq.js +0 -1
  490. package/build/assets/agent-server-adapter-k8veH-1O.js +0 -5
  491. package/build/assets/agent-server-client-options-B-C8JaTb.js +0 -1
  492. package/build/assets/agent-server-conversation-service.api-CGbkhsLj.js +0 -1
  493. package/build/assets/api-key-entry-screen-Dnr5TcV0.js +0 -1
  494. package/build/assets/app-settings-Bgm2-yOM.js +0 -1
  495. package/build/assets/automation-detail-86M_yMqz.js +0 -1
  496. package/build/assets/automations-list-BWUILrqY.js +0 -1
  497. package/build/assets/backend-form-modal-Dl29wkF5.js +0 -1
  498. package/build/assets/browser-store-JRrcGdlk.js +0 -1
  499. package/build/assets/browser-wz8UzRmF.js +0 -5
  500. package/build/assets/chat-send-button-BhoO7T0s.js +0 -1
  501. package/build/assets/check-BhnsMsWy.js +0 -1
  502. package/build/assets/condenser-settings-DgQ0rsAf.js +0 -1
  503. package/build/assets/context-CI9FqkUp.js +0 -1
  504. package/build/assets/conversation-CayU5Lrr.js +0 -19
  505. package/build/assets/conversation-erinyBqT.js +0 -1
  506. package/build/assets/conversation-panel-DiI4q-8-.js +0 -1
  507. package/build/assets/conversation-service.api-shHWtFwu.js +0 -1
  508. package/build/assets/conversation-state-store-NEktJKfL.js +0 -1
  509. package/build/assets/declaration-D9ucT0fq.js +0 -1
  510. package/build/assets/dist-BCpEDEJq.js +0 -1
  511. package/build/assets/edit-automation-modal-8y9Uctxo.js +0 -1
  512. package/build/assets/entry.client-D_wtryHT.js +0 -2
  513. package/build/assets/files-tab-CxdtgkIe.js +0 -1
  514. package/build/assets/files-tab-store-DSKUhziI.js +0 -1
  515. package/build/assets/home-3joHMYSR.js +0 -1
  516. package/build/assets/index-redirect-BQ_55qN6.js +0 -1
  517. package/build/assets/install-server-modal-_7l1gcjd.js +0 -1
  518. package/build/assets/lesson-plan-CHGc-B8Y.js +0 -3
  519. package/build/assets/llm-not-configured-banner-BMGzpBPV.js +0 -27
  520. package/build/assets/llm-settings-BRotm_g6.js +0 -1
  521. package/build/assets/llm-settings-yDgbXP6Q.js +0 -1
  522. package/build/assets/loader-circle-1XB9nbwF.js +0 -1
  523. package/build/assets/manage-backends-modal-tfdzTXWU.js +0 -1
  524. package/build/assets/manifest-bbc1374e.js +0 -1
  525. package/build/assets/markdown-renderer-z446oW0Z.js +0 -2
  526. package/build/assets/mcp-Dopstf0t.js +0 -9
  527. package/build/assets/mcp-settings-redirect-l3Zbmc0F.js +0 -1
  528. package/build/assets/messages-CsFUrAen.js +0 -41
  529. package/build/assets/model-selector-sioC8xP4.js +0 -1
  530. package/build/assets/onboarding-CQh50i2z.js +0 -1
  531. package/build/assets/option-service.api-DjPvPAtd.js +0 -1
  532. package/build/assets/organization-service.api-BNc9Kn6n.js +0 -1
  533. package/build/assets/plus-DKUID4kd.js +0 -1
  534. package/build/assets/providers-BiWSYwRT.js +0 -1
  535. package/build/assets/proxy--Uy1iGsW.js +0 -1
  536. package/build/assets/query-client-config-Ca3tW1AH.js +0 -1
  537. package/build/assets/root-CRkz_h2T.css +0 -1
  538. package/build/assets/root-DrHpnAqU.js +0 -2
  539. package/build/assets/root-layout-Cf7FC9DC.js +0 -2
  540. package/build/assets/sdk-section-page-COlGKv4E.js +0 -1
  541. package/build/assets/sdk-settings-schema-Big50zDH.js +0 -1
  542. package/build/assets/secrets-settings-DYfTc5c8.js +0 -1
  543. package/build/assets/settings-DRmVFdOc.js +0 -1
  544. package/build/assets/settings-modal-CeRvS5Bc.js +0 -1
  545. package/build/assets/settings-service.api-CFt5HmXD.js +0 -1
  546. package/build/assets/shared-conversation-CBbpyPaD.js +0 -1
  547. package/build/assets/sidebar-mobile-menu-toggle-SKcwsEtD.js +0 -1
  548. package/build/assets/suspense-Bqb0V0q1.js +0 -1
  549. package/build/assets/telemetry-DCFAqpIA.js +0 -2
  550. package/build/assets/use-acp-credential-form-LjCIhMSK.js +0 -1
  551. package/build/assets/use-agent-settings-schema-D8x5LJVS.js +0 -1
  552. package/build/assets/use-config-5zEjywCL.js +0 -1
  553. package/build/assets/use-create-conversation-pV2eA-e9.js +0 -1
  554. package/build/assets/use-handle-plan-click-CwN_nNib.js +0 -1
  555. package/build/assets/use-is-authed-B8eLO-Xq.js +0 -1
  556. package/build/assets/use-llm-profiles-CWLfWjav.js +0 -1
  557. package/build/assets/use-runtime-is-ready-Bbory9-s.js +0 -1
  558. package/build/assets/use-save-settings-Xp8DD-jf.js +0 -1
  559. package/build/assets/use-settings-0SeqaDeW.js +0 -1
  560. package/build/assets/useMutation-Dm84WAKR.js +0 -1
  561. package/build/assets/useQuery-DGRSm7IT.js +0 -1
  562. package/build/assets/useTranslation-CL6FTf1b.js +0 -1
  563. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~dqseey1n-D_BSEDk4.js +0 -1
  564. package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~jfbjdnyv-C5ZIbuq8.js +0 -177
  565. package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~mcp~settings~settings-index~~m3acswdn-CGm-Jxp5.js +0 -48
  566. package/build/assets/x-CCfDppg5.js +0 -1
  567. package/dist/api/settings-service/legacy-app-preferences-migration.cjs +0 -2
  568. package/dist/api/settings-service/legacy-app-preferences-migration.cjs.map +0 -1
  569. package/dist/api/settings-service/legacy-app-preferences-migration.d.ts +0 -34
  570. package/dist/api/settings-service/legacy-app-preferences-migration.js +0 -52
  571. package/dist/api/settings-service/legacy-app-preferences-migration.js.map +0 -1
  572. package/dist/hooks/query/use-openhands-verified-models.cjs +0 -2
  573. package/dist/hooks/query/use-openhands-verified-models.cjs.map +0 -1
  574. package/dist/hooks/query/use-openhands-verified-models.d.ts +0 -1
  575. package/dist/hooks/query/use-openhands-verified-models.js +0 -14
  576. package/dist/hooks/query/use-openhands-verified-models.js.map +0 -1
  577. package/dist/utils/normalize-display-model.cjs +0 -2
  578. package/dist/utils/normalize-display-model.cjs.map +0 -1
  579. package/dist/utils/normalize-display-model.d.ts +0 -9
  580. package/dist/utils/normalize-display-model.js +0 -13
  581. package/dist/utils/normalize-display-model.js.map +0 -1
  582. package/dist/utils/openhands-llm.cjs +0 -2
  583. package/dist/utils/openhands-llm.cjs.map +0 -1
  584. package/dist/utils/openhands-llm.d.ts +0 -15
  585. package/dist/utils/openhands-llm.js +0 -15
  586. package/dist/utils/openhands-llm.js.map +0 -1
  587. /package/build/assets/{agent-server-ui-style-scope-BwIZYdC1.js → agent-server-ui-style-scope-1MuaCC1k.js} +0 -0
  588. /package/build/assets/{common-Dh7OqABE.js → common-DqjLSBOt.js} +0 -0
  589. /package/build/assets/{environment-switch-store-CiurvTtK.js → environment-switch-store-CBXkf5bS.js} +0 -0
  590. /package/build/assets/{extension-module-card-classes-DP5J6ngE.js → extension-module-card-classes-CVGfXtoL.js} +0 -0
  591. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DVFXF1_X.js} +0 -0
  592. /package/build/assets/{handle-capture-consent-CPMXU29K.js → handle-capture-consent-BTvatyfE.js} +0 -0
  593. /package/build/assets/{map-provider-BM2SJarp.js → map-provider-COgsZR9p.js} +0 -0
  594. /package/build/assets/{objectWithoutPropertiesLoose-DSQKyRhw.js → objectWithoutPropertiesLoose-B80nTzVc.js} +0 -0
  595. /package/build/assets/{preload-helper-CT1Z6Pdu.js → preload-helper-D_sPnjeL.js} +0 -0
  596. /package/build/assets/{rolldown-runtime-BFRubm34.js → rolldown-runtime-wFmyQBCi.js} +0 -0
  597. /package/build/assets/{sdk-settings-field-metadata-p2GVlft7.js → sdk-settings-field-metadata-Cc4D-ut7.js} +0 -0
  598. /package/build/assets/{settings-wh2sLLJM.js → settings-1287uR2J.js} +0 -0
  599. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~nh19ovoo-DJTFnsA1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~cg1m3bv7-aUIHudsf.js} +0 -0
  600. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-BmZcy_kH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-DPPGSgT1.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"agent-server-adapter.js","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { ACP_SETTINGS_KEYS } from \"@openhands/typescript-client\";\nimport { SKILLS_CATALOG } from \"@openhands/extensions/skills\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpPreferredDefaultModel,\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport { getAgentServerWorkingDir } from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of the runtime services info (set by the dev launchers in\n * scripts/dev-*.mjs as `VITE_RUNTIME_SERVICES_INFO`, or injected at serve time\n * by `scripts/static-server.mjs` for static builds — see\n * `getRawRuntimeServicesInfo`). All URLs are written from the agent's point of\n * view, not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\n/**\n * Return the raw runtime-services JSON string, consulting two sources in order\n * (mirrors `getBakedSessionApiKey` in agent-server-config.ts):\n * 1. `VITE_RUNTIME_SERVICES_INFO` — baked into the bundle at build time by\n * the dev launchers (`npm run dev`, dev:static).\n * 2. `window.__AGENT_CANVAS_RUNTIME_SERVICES_INFO__` — injected into\n * index.html at serve time by `scripts/static-server.mjs\n * --runtime-services-info <json>`. This is the path used by static builds\n * (the Docker image and the published binary), where the env var is empty\n * in the prebuilt bundle. Without it the `<RUNTIME_SERVICES>` block is\n * missing and the agent cannot reach the local automation backend.\n */\nfunction getRawRuntimeServicesInfo(): string | null {\n const envRaw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (envRaw) return envRaw;\n\n if (typeof window !== \"undefined\") {\n const injected = (window as unknown as Record<string, unknown>)\n .__AGENT_CANVAS_RUNTIME_SERVICES_INFO__;\n if (typeof injected === \"string\") {\n return injected.trim() || null;\n }\n }\n\n return null;\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = getRawRuntimeServicesInfo();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured env var or\n // injected value.\n return null;\n }\n}\n\n/**\n * Return the deployment mode from the runtime services info, e.g. \"docker\",\n * \"dev:automation\", etc. Returns `null` when no runtime info is configured.\n */\nexport function getDeploymentMode(): string | null {\n return parseRuntimeServicesInfo()?.mode ?? null;\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n // X-Session-API-Key is the local convention shared by the agent-server\n // and automation backend (see openhands-automation auth.py).\n lines.push(\n ` Auth: header 'X-Session-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n active_profile: metadata?.active_profile ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\n/**\n * Shape of a bundled skill entry passed to the agent-server SDK via\n * `agent_context.skills`. Mirrors the SDK's `Skill` model fields that\n * the server uses for trigger matching, activation, and system-prompt\n * injection.\n */\ninterface BundledSkill {\n name: string;\n content: string;\n trigger: { type: \"keyword\"; keywords: string[] } | null;\n source: \"public\";\n description: string | null;\n is_agentskills_format: true;\n license?: string;\n compatibility?: string;\n}\n\n/**\n * Convert the bundled `SKILLS_CATALOG` entries into the SDK `Skill` JSON\n * shape so the agent-server can perform trigger matching, skill activation,\n * and system-prompt injection without cloning the extensions repo.\n *\n * The SDK discriminates triggers via `{ type: \"keyword\", keywords: [...] }`.\n * Skills with no triggers get `trigger: null` (always-active / on-demand).\n */\nfunction buildBundledSkills(): BundledSkill[] {\n return SKILLS_CATALOG.map((entry) => {\n const trigger: BundledSkill[\"trigger\"] =\n entry.triggers?.length > 0\n ? { type: \"keyword\", keywords: entry.triggers }\n : null;\n\n return {\n name: entry.name,\n content: entry.content,\n trigger,\n source: \"public\" as const,\n description: entry.description ?? null,\n is_agentskills_format: true as const,\n ...(entry.license ? { license: entry.license } : {}),\n ...(entry.compatibility ? { compatibility: entry.compatibility } : {}),\n };\n });\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n const existingContext = toRecord(agentSettings.agent_context);\n\n // Merge bundled public skills with any skills already present in the\n // agent context (e.g. user-defined skills set via the settings API).\n const existingSkills = Array.isArray(existingContext.skills)\n ? (existingContext.skills as SettingsRecord[])\n : [];\n const mergedSkills = [...existingSkills, ...buildBundledSkills()];\n\n return {\n ...existingContext,\n // Public skills are bundled at build time from the @openhands/extensions\n // npm package and passed directly in agent_context.skills. Setting\n // load_public_skills to false tells the agent-server SDK to skip its own\n // extensions-repo clone — the frontend is the sole source of public\n // skills now.\n //\n // Migration: the former VITE_LOAD_PUBLIC_SKILLS env var was removed\n // because bundled skills have no clone latency. Users who previously set\n // VITE_LOAD_PUBLIC_SKILLS=false to avoid clone delays no longer need it.\n skills: mergedSkills,\n load_public_skills: false,\n load_user_skills: true,\n load_project_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n // TODO(#1019): set ``acp_isolate_data_dir: true`` here for a containerized\n // backend so concurrent same-provider conversations don't race on a shared\n // HOME. The SDK supports it (software-agent-sdk#3492), but the released\n // ``@openhands/typescript-client`` (1.24.3) doesn't surface it on\n // ``ACPAgentSettings`` yet, so sending it risks a validation error on older\n // servers. Cloud grouping isolation is separate (agent-canvas#1016).\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n // ``acp_env`` is deprecated — provider creds now route via ``request.secrets``.\n if (key === \"acp_env\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // ``mcp_config`` is a *shared* field (not in ACP_SETTINGS_KEYS): forward it\n // so the ACP subprocess connects to the configured MCP servers at session\n // creation. Only include it when it actually carries servers — an empty or\n // malformed value is dropped rather than sending ``mcp_config: {}``.\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length > 0 && \"mcpServers\" in mcpConfig) {\n payload.mcp_config = mcpConfig;\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the *preferred* default (Vertex-safe for Gemini) so the\n // conversation starts with whatever the Settings → Agent UI shows — without\n // that, the form's displayed default would silently not take effect at\n // runtime until the user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: getAcpPreferredDefaultModel(serverKey),\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" && llm.model.trim().length > 0\n ? llm.model\n : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n // ``acp_env`` is no longer a forwarded ACP setting (provider creds ride the\n // Secrets panel), but a legacy value may linger on persisted settings —\n // scrub it so it never leaks onto the OpenHands payload.\n delete agentSettings.acp_env;\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: boolean;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n worktree?: boolean;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: options.worktree ?? true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n // ``secrets_encrypted`` makes the agent-server run every request secret through\n // ``cipher.decrypt()`` at conversation start. Suppress it for ACP: an ACP agent\n // carries no encrypted payload (no LLM api_key, and credentials ride as\n // LookupSecrets whose values are fetched at resolution time, not decrypted), so\n // there is nothing to decrypt. Claiming otherwise hard-fails (\"cipher not\n // configured\") on a backend without ``OH_SECRET_KEY`` (e.g. a fresh ACP\n // container). Non-ACP conversations still need it for their encrypted LLM key.\n if (options.secretsEncrypted && !acpMode) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n // Every saved secret rides as a LookupSecret the agent-server resolves back\n // from its own store at spawn time — ``request.secrets`` is the sole channel,\n // uniform for ACP and non-ACP (agent-canvas#1039). For ACP the resolution\n // runs off the event loop (software-agent-sdk#3510, ≥1.25.0), so the loopback\n // fetch can't deadlock.\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = backend ? buildAuthHeaders(backend) : {};\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n worktree?: boolean;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-server-adapter.js","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { ACP_SETTINGS_KEYS } from \"@openhands/typescript-client\";\nimport { SKILLS_CATALOG } from \"@openhands/extensions/skills\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpPreferredDefaultModel,\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport { getAgentServerWorkingDir } from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\nimport LLMSubscriptionService from \"./llm-subscription-service\";\nimport {\n LLM_AUTH_TYPE_SUBSCRIPTION,\n OPENAI_SUBSCRIPTION_VENDOR,\n isSubscriptionLlmConfig,\n} from \"#/constants/llm-subscription\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of the runtime services info (set by the dev launchers in\n * scripts/dev-*.mjs as `VITE_RUNTIME_SERVICES_INFO`, or injected at serve time\n * by `scripts/static-server.mjs` for static builds — see\n * `getRawRuntimeServicesInfo`). All URLs are written from the agent's point of\n * view, not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\n/**\n * Return the raw runtime-services JSON string, consulting two sources in order\n * (mirrors `getBakedSessionApiKey` in agent-server-config.ts):\n * 1. `VITE_RUNTIME_SERVICES_INFO` — baked into the bundle at build time by\n * the dev launchers (`npm run dev`, dev:static).\n * 2. `window.__AGENT_CANVAS_RUNTIME_SERVICES_INFO__` — injected into\n * index.html at serve time by `scripts/static-server.mjs\n * --runtime-services-info <json>`. This is the path used by static builds\n * (the Docker image and the published binary), where the env var is empty\n * in the prebuilt bundle. Without it the `<RUNTIME_SERVICES>` block is\n * missing and the agent cannot reach the local automation backend.\n */\nfunction getRawRuntimeServicesInfo(): string | null {\n const envRaw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (envRaw) return envRaw;\n\n if (typeof window !== \"undefined\") {\n const injected = (window as unknown as Record<string, unknown>)\n .__AGENT_CANVAS_RUNTIME_SERVICES_INFO__;\n if (typeof injected === \"string\") {\n return injected.trim() || null;\n }\n }\n\n return null;\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = getRawRuntimeServicesInfo();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured env var or\n // injected value.\n return null;\n }\n}\n\n/**\n * Return the deployment mode from the runtime services info, e.g. \"docker\",\n * \"dev:automation\", etc. Returns `null` when no runtime info is configured.\n */\nexport function getDeploymentMode(): string | null {\n return parseRuntimeServicesInfo()?.mode ?? null;\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n const { frontend } = info.services;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n // X-Session-API-Key is the local convention shared by the agent-server\n // and automation backend (see openhands-automation auth.py).\n lines.push(\n ` Auth: header 'X-Session-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n active_profile: metadata?.active_profile ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === CANVAS_UI_TOOL_NAME) {\n return isAgentServerToolAvailable(name);\n }\n\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\n/**\n * Shape of a bundled skill entry passed to the agent-server SDK via\n * `agent_context.skills`. Mirrors the SDK's `Skill` model fields that\n * the server uses for trigger matching, activation, and system-prompt\n * injection.\n */\ninterface BundledSkill {\n name: string;\n content: string;\n trigger: { type: \"keyword\"; keywords: string[] } | null;\n source: \"public\";\n description: string | null;\n is_agentskills_format: true;\n license?: string;\n compatibility?: string;\n}\n\n/**\n * Convert the bundled `SKILLS_CATALOG` entries into the SDK `Skill` JSON\n * shape so the agent-server can perform trigger matching, skill activation,\n * and system-prompt injection without cloning the extensions repo.\n *\n * The SDK discriminates triggers via `{ type: \"keyword\", keywords: [...] }`.\n * Skills with no triggers get `trigger: null` (always-active / on-demand).\n */\nfunction buildBundledSkills(): BundledSkill[] {\n return SKILLS_CATALOG.map((entry) => {\n const trigger: BundledSkill[\"trigger\"] =\n entry.triggers?.length > 0\n ? { type: \"keyword\", keywords: entry.triggers }\n : null;\n\n return {\n name: entry.name,\n content: entry.content,\n trigger,\n source: \"public\" as const,\n description: entry.description ?? null,\n is_agentskills_format: true as const,\n ...(entry.license ? { license: entry.license } : {}),\n ...(entry.compatibility ? { compatibility: entry.compatibility } : {}),\n };\n });\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n const existingContext = toRecord(agentSettings.agent_context);\n\n // Merge bundled public skills with any skills already present in the\n // agent context (e.g. user-defined skills set via the settings API).\n const existingSkills = Array.isArray(existingContext.skills)\n ? (existingContext.skills as SettingsRecord[])\n : [];\n const mergedSkills = [...existingSkills, ...buildBundledSkills()];\n\n return {\n ...existingContext,\n // Public skills are bundled at build time from the @openhands/extensions\n // npm package and passed directly in agent_context.skills. Setting\n // load_public_skills to false tells the agent-server SDK to skip its own\n // extensions-repo clone — the frontend is the sole source of public\n // skills now.\n //\n // Migration: the former VITE_LOAD_PUBLIC_SKILLS env var was removed\n // because bundled skills have no clone latency. Users who previously set\n // VITE_LOAD_PUBLIC_SKILLS=false to avoid clone delays no longer need it.\n skills: mergedSkills,\n load_public_skills: false,\n load_user_skills: true,\n load_project_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n // TODO(#1019): set ``acp_isolate_data_dir: true`` here for a containerized\n // backend so concurrent same-provider conversations don't race on a shared\n // HOME. The SDK supports it (software-agent-sdk#3492), but the released\n // ``@openhands/typescript-client`` (1.24.3) doesn't surface it on\n // ``ACPAgentSettings`` yet, so sending it risks a validation error on older\n // servers. Cloud grouping isolation is separate (agent-canvas#1016).\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n // ``acp_env`` is deprecated — provider creds now route via ``request.secrets``.\n if (key === \"acp_env\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // ``mcp_config`` is a *shared* field (not in ACP_SETTINGS_KEYS): forward it\n // so the ACP subprocess connects to the configured MCP servers at session\n // creation. Only include it when it actually carries servers — an empty or\n // malformed value is dropped rather than sending ``mcp_config: {}``.\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length > 0 && \"mcpServers\" in mcpConfig) {\n payload.mcp_config = mcpConfig;\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the *preferred* default (Vertex-safe for Gemini) so the\n // conversation starts with whatever the Settings → Agent UI shows — without\n // that, the form's displayed default would silently not take effect at\n // runtime until the user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: getAcpPreferredDefaultModel(serverKey),\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" && llm.model.trim().length > 0\n ? llm.model\n : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n if (isSubscriptionLlmConfig(llm)) {\n llm.auth_type = LLM_AUTH_TYPE_SUBSCRIPTION;\n llm.subscription_vendor = OPENAI_SUBSCRIPTION_VENDOR;\n delete llm.api_key;\n delete llm.base_url;\n } else {\n delete llm.auth_type;\n delete llm.subscription_vendor;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n // ``acp_env`` is no longer a forwarded ACP setting (provider creds ride the\n // Secrets panel), but a legacy value may linger on persisted settings —\n // scrub it so it never leaks onto the OpenHands payload.\n delete agentSettings.acp_env;\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: boolean;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n worktree?: boolean;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: options.worktree ?? true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n // ``secrets_encrypted`` makes the agent-server run every request secret through\n // ``cipher.decrypt()`` at conversation start. Suppress it for ACP: an ACP agent\n // carries no encrypted payload (no LLM api_key, and credentials ride as\n // LookupSecrets whose values are fetched at resolution time, not decrypted), so\n // there is nothing to decrypt. Claiming otherwise hard-fails (\"cipher not\n // configured\") on a backend without ``OH_SECRET_KEY`` (e.g. a fresh ACP\n // container). Non-ACP conversations still need it for their encrypted LLM key.\n if (options.secretsEncrypted && !acpMode) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n const toolModuleQualnames: Record<string, string> = {};\n const canvasUiAvailable = isAgentServerToolAvailable(CANVAS_UI_TOOL_NAME);\n if (canvasUiAvailable) {\n toolModuleQualnames[CANVAS_UI_TOOL_NAME] = CANVAS_UI_TOOL_MODULE;\n }\n Object.assign(\n toolModuleQualnames,\n (conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {},\n );\n if (!canvasUiAvailable) {\n delete toolModuleQualnames[CANVAS_UI_TOOL_NAME];\n }\n if (Object.keys(toolModuleQualnames).length > 0) {\n payload.tool_module_qualnames = toolModuleQualnames;\n }\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n // Every saved secret rides as a LookupSecret the agent-server resolves back\n // from its own store at spawn time — ``request.secrets`` is the sole channel,\n // uniform for ACP and non-ACP (agent-canvas#1039). For ACP the resolution\n // runs off the event loop (software-agent-sdk#3510, >=1.25.0), so the loopback\n // fetch can't deadlock.\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = backend ? buildAuthHeaders(backend) : {};\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n }\n\n return payload;\n}\n\nexport const SUBSCRIPTION_LOGIN_REQUIRED_ERROR =\n \"Connect your ChatGPT subscription before starting a conversation with this LLM profile.\";\n\n/**\n * Throws if a ChatGPT subscription LLM profile is not connected.\n * Called before conversation creation and LLM profile switch only — not on\n * subsequent message sends or conversation resume. The agent-server must handle\n * mid-conversation token expiry gracefully.\n */\nexport async function assertSubscriptionAuthReady(\n agentSettings: Record<string, unknown>,\n): Promise<void> {\n const llm = toRecord(agentSettings.llm);\n if (!isSubscriptionLlmConfig(llm)) return;\n\n const status = await LLMSubscriptionService.getOpenAIStatus();\n if (!status.connected) {\n throw new Error(SUBSCRIPTION_LOGIN_REQUIRED_ERROR);\n }\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n worktree?: boolean;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n await assertSubscriptionAuthReady(agentSettings);\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkFA,IAAM,IAAsB,aACtB,IAAwB,kBAExB,IAAqB;CACzB;CACA;CACA;CACA;CACD,EACK,IAAwB,oBACxB,IAAqB;AAE3B,SAAS,IAAsB;AAC7B,QAAO;;AAiDT,SAAS,IAA2C;CAClD,IAAM,KAAA,KAAA,IAAqD,MAAM;AACjE,KAAI,EAAQ,QAAO;AAEnB,KAAI,OAAO,SAAW,KAAa;EACjC,IAAM,IAAY,OACf;AACH,MAAI,OAAO,KAAa,SACtB,QAAO,EAAS,MAAM,IAAI;;AAI9B,QAAO;;AAGT,SAAS,IAAuD;CAC9D,IAAM,IAAM,GAA2B;AACvC,KAAI,CAAC,EAAK,QAAO;AACjB,KAAI;EACF,IAAM,IAAS,KAAK,MAAM,EAAI;AAE9B,SADI,CAAC,KAAU,OAAO,KAAW,WAAiB,OAC3C;SACD;AAIN,SAAO;;;AAoBX,SAAgB,IAAuD;CACrE,IAAM,IAAO,GAA0B;AACvC,KAAI,CAAC,GAAM,SAAU;CAErB,IAAM,IAAkB,EAAE;AAS1B,CARA,EAAM,KAAK,qBAAqB,EAC5B,EAAK,OACP,EAAM,KACJ,gEAAgE,EAAK,KAAK,SAC3E,GAED,EAAM,KAAK,oDAAoD,EAEjE,EAAM,KACJ,4EACA,kEACA,GACD;CAED,IAAM,EAAE,iBAAc,YAAS,kBAAe,EAAK,UAC7C,EAAE,gBAAa,EAAK;AAoB1B,CAlBI,GAAc,kBAChB,EAAM,KACJ,yBAAyB,EAAa,kBACtC,OAAO,EAAa,eAAe,8CACpC,EAEC,GAAS,kBACX,EAAM,KACJ,cAAc,EAAQ,kBACtB,OAAO,EAAQ,eAAe,oDAC/B,EAEC,GAAU,kBACZ,EAAM,KACJ,eAAe,EAAS,kBACxB,OAAO,EAAS,eAAe,yBAChC,EAEC,GAAY,kBACd,EAAM,KACJ,yBAAyB,EAAW,kBACpC,OAAO,EAAW,eAAe,mCAClC,EACG,EAAW,YACb,EAAM,KAAK,gBAAgB,EAAW,WAAW,EAE/C,EAAW,eACb,EAAM,KAAK,gBAAgB,EAAW,cAAc,EAElD,EAAW,gBAGb,EAAM,KACJ,4CAA4C,EAAW,aAAa,GACrE,IAGH,EAAM,KACJ,mFACD;CAQH,IAAM,IAAiB,GAAc;AAarC,QAZA,EAAM,KACJ,IACA,4EACD,EACG,KACF,EAAM,KACJ,kBAAkB,EAAe,2CACjC,0DACD,EAEH,EAAM,KAAK,sBAAsB,EAE1B,EAAM,KAAK,KAAK;;AAGzB,SAAgB,EAAkB,GAAgC;CAIhE,IAAM,EAAE,YAAS,GAA6B;AAC9C,QAAO,GAAG,EAAK,qBAAqB;;AAMtC,SAAgB,EAA4B,GAAgC;AAC1E,QAAO,gBAAgB,EAAe,MAAM,GAAG,EAAE;;AAGnD,SAAgB,EACd,GACiB;CACjB,IAAM,IAAW,EAA8B,EAAK,GAAG,EAKjD,IAAQ,EAAK,OAAO,SAAS,YAK7B,IAAY,IAAS,EAAK,MAAA,aAA8B,OAAQ;AACtE,QAAO;EACL,IAAI,EAAK;EACT,oBAAoB;EACpB,qBAAqB,GAAU,uBAAuB;EACtD,iBAAiB,GAAU,mBAAmB;EAC9C,cAAc,GAAU,gBAAgB;EACxC,oBAAoB,GAAU,sBAAsB;EACpD,gBAAgB,GAAU,kBAAkB;EAC5C,OAAO,EAAK,OAAO,MAAM,GACrB,EAAK,QACL,EAA4B,EAAK,GAAG;EACxC,SAAS;EACT,WAAW,EAAE;EACb,YAAY,IAAQ,QAAQ;EAC5B,YAAY;EAKZ,WAAW,IACP,EAAyB;GACvB,aAAa,EAAK;GAClB,WAAW,EAAK;GAChB,YAAY,EAAK,OAAO;GACxB,QAAQ,EAAK,OAAO,KAAK;GAC1B,CAAC,GACD,EAAK,OAAO,KAAK,SAAS,EAAiB;EAChD,SAAS,EAAK,UACV;GACE,kBAAkB,EAAK,QAAQ,oBAAoB;GACnD,qBAAqB,EAAK,QAAQ,uBAAuB;GACzD,yBAAyB,EAAK,QAAQ,0BAClC;IACE,eACE,EAAK,QAAQ,wBAAwB,iBAAiB;IACxD,mBACE,EAAK,QAAQ,wBAAwB,qBAAqB;IAC5D,mBACE,EAAK,QAAQ,wBAAwB,qBAAqB;IAC5D,oBACE,EAAK,QAAQ,wBAAwB,sBAAsB;IAC7D,gBACE,EAAK,QAAQ,wBAAwB,kBAAkB;IACzD,gBACE,EAAK,QAAQ,wBAAwB,kBAAkB;IAC1D,GACD;GACL,GACD;EACJ,YAAY,EAAK;EACjB,YAAY,EAAK;EACjB,kBACG,EAAK,oBACN,EAAgB;EAClB,gBAAiB,EAAK,kBAA2C;EACjE,kBAAkB,EAAkB,EAAK,GAAG;EAC5C,iBAAiB,GAA6B,CAAC,UAAU;EACzD,YAAY;EACZ,WAAW,EACT,aAAa,EAAK,WAAW,eAAe,GAA0B,EACvE;EACD,QAAQ;EACR,sBAAsB,EAAE;EACzB;;AAGH,SAAgB,EAAmB,GAGX;AACtB,QAAO;EACL,OAAO,EAAK,MAAM,IAAI,EAAkB;EACxC,cAAc,EAAK,gBAAgB;EACpC;;AAgCH,IAAa,IAAqB,aAE5B,IAAsC,IAAI,IAAI;CAClD;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,EAAS,GAAgC;AAKhD,QAJI,CAAC,KAAS,OAAO,KAAU,YAAY,MAAM,QAAQ,EAAM,GACtD,EAAE,GAGJ,gBAAgB,EAAwB;;AAGjD,SAAS,EAAsB,GAAoC;AACjE,KAAI,OAAO,KAAU,SACnB;CAGF,IAAM,IAAU,EAAM,MAAM;AAC5B,QAAO,EAAQ,SAAS,IAAI,IAAU,KAAA;;AAGxC,SAAS,EACP,GACA;AASA,QARI,EAAqB,sBAAsB,KAI3C,EAAqB,sBAAsB,QACtC;EAAE,MAAM;EAAgB,WAAW;EAAQ,iBAAiB;EAAM,GAGpE,EAAE,MAAM,iBAAiB,GAPvB,EAAE,MAAM,gBAAgB;;AAUnC,SAAS,EAAgC,GAAsC;AAC7E,SAAQ,EAAqB,mBAA7B;EACE,KAAK,MACH,QAAO,EAAE,MAAM,uBAAuB;EACxC,KAAK,UACH,QAAO,EAAE,MAAM,2BAA2B;EAC5C,KAAK,cACH,QAAO,EAAE,MAAM,8BAA8B;EAC/C,QACE;;;AAIN,SAAS,EACP,GAC6C;AAC7C,QACE,CAAC,CAAC,KACF,OAAO,KAAU,YACjB,CAAC,MAAM,QAAQ,EAAM,IACrB,OAAQ,EAA6B,QAAS;;AAIlD,SAAS,EAAkB,GAAc,GAA+B;AAgBtE,QAfI,MAAS,IACJ,EAA2B,EAAK,GAGrC,MAAS,IACJ,GAAqB,IAAI,EAA2B,EAAK,GAG9D,MAAS,IAET,EAAc,sBAAsB,MACpC,EAA2B,EAAK,GAI7B;;AAGT,SAAS,EAAc,GAAgD;CACrE,IAAM,oBAAQ,IAAI,KAA4B;AAE9C,MAAK,IAAM,KAAQ,EACjB,CAAI,EAAkB,GAAM,EAAc,IACxC,EAAM,IAAI,GAAM;EAAE;EAAM,QAAQ,EAAE;EAAE,CAAC;AAIzC,MAAK,IAAM,KAAQ,CAAC,GAAuB,EAAmB,CAC5D,CAAI,EAAkB,GAAM,EAAc,IACxC,EAAM,IAAI,GAAM;EAAE;EAAM,QAAQ,EAAE;EAAE,CAAC;CAIzC,IAAM,IAAkB,EAAc;AACtC,KACE,MAAM,QAAQ,EAAgB,IAC9B,EAAgB,OAAO,MAAS,EAAa,EAAK,CAAC,OAE9C,IAAM,KAAQ,EACjB,CAAI,EAAkB,EAAK,MAAM,EAAc,IAC7C,EAAM,IAAI,EAAK,MAAM;EACnB,MAAM,EAAK;EACX,QAAQ,EAAS,EAAK,OAAO;EAC9B,CAAC;AAKR,QAAO,MAAM,KAAK,EAAM,QAAQ,CAAC;;AAGnC,SAAS,EACP,GACA,GAC8B;CAC9B,IAAM,IAAQ,CAAC,GAAO,MAAM,EAAE,GAA0B,MAAM,CAAC,CAAC,OAC9D,QACD;AAKD,QAJI,EAAM,WAAW,IACZ,OAGF;EACL,MAAM;EACN,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,EAAM,KAAK,OAAO;GAAE,CAAC;EACrD,KAAK;EACN;;AA4BH,SAAS,IAAqC;AAC5C,QAAO,EAAe,KAAK,MAAU;EACnC,IAAM,IACJ,EAAM,UAAU,SAAS,IACrB;GAAE,MAAM;GAAW,UAAU,EAAM;GAAU,GAC7C;AAEN,SAAO;GACL,MAAM,EAAM;GACZ,SAAS,EAAM;GACf;GACA,QAAQ;GACR,aAAa,EAAM,eAAe;GAClC,uBAAuB;GACvB,GAAI,EAAM,UAAU,EAAE,SAAS,EAAM,SAAS,GAAG,EAAE;GACnD,GAAI,EAAM,gBAAgB,EAAE,eAAe,EAAM,eAAe,GAAG,EAAE;GACtE;GACD;;AAGJ,SAAS,EAAkB,GAA+C;CACxE,IAAM,IAAwB,GAAkC,EAC1D,IAAkB,EAAS,EAAc,cAAc,EAOvD,IAAe,CAAC,GAHC,MAAM,QAAQ,EAAgB,OAAO,GACvD,EAAgB,SACjB,EAAE,EACmC,GAAG,GAAoB,CAAC;AAEjE,QAAO;EACL,GAAG;EAUH,QAAQ;EACR,oBAAoB;EACpB,kBAAkB;EAClB,qBAAqB;EACrB,GAAI,IACA,EAAE,uBAAuB,GAAuB,GAChD,EAAE;EACP;;AAGH,SAAS,EAAW,GAA6B;AAE/C,QADsB,EAAS,EAAS,eACjC,CAAc,eAAe;;AAGtC,SAAS,EAAgB,GAAwC;CAE/D,IAAM,IADgB,EAAS,EAAS,eAC1B,CAAc;AAC5B,QAAO,OAAO,KAAU,YAAY,EAAM,SAAS,IAAI,IAAQ,KAAA;;AAGjE,SAAS,EAAkB,GAAwC;CACjE,IAAM,IAAM,EAAc;AAG1B,KAAI,EAFY,MAAM,QAAQ,EAAI,IAAI,EAAI,WAAW,MACnC,MAAQ,KAAA,EAExB,QAAO;CAOT,IAAM,IAAW,EAHf,OAAO,EAAc,cAAe,WAChC,EAAc,aACd,KAAA,EACoC;AAC1C,QAAO,IAAW,CAAC,GAAG,EAAS,gBAAgB,GAAG;;AAGpD,SAAS,EACP,GACsB;CACtB,IAAM,IAAgB,EAAS,EAAS,eAAe,EACjD,IAAgC;EACpC,YAAY;EACZ,eAAe,EAAkB,EAAc;EAChD;AASD,MAAK,IAAM,KAAO,GAAmB;AAKnC,MAFI,MAAQ,eAER,MAAQ,UAAW;EACvB,IAAM,IACJ,MAAQ,gBACJ,EAAkB,EAAc,GAChC,EAAc;AACpB,EAAI,KAAiC,SACnC,EAAQ,KAAO;;CAQnB,IAAM,IAAY,EAAS,EAAc,WAAW;AACpD,CAAI,OAAO,KAAK,EAAU,CAAC,SAAS,KAAK,gBAAgB,MACvD,EAAQ,aAAa;CASvB,IAAM,IACJ,OAAO,EAAc,cAAe,WAChC,EAAc,aACd,KAAA,GACA,IAAiB,EAAyB;EAC9C,YAAY,EAAc;EAC1B,iBAAiB,EAA4B,EAAU;EACxD,CAAC;AAKF,QAJI,MACF,EAAQ,YAAY,IAGf;;AAGT,SAAS,EACP,GACsB;CACtB,IAAM,IAAgB,EAAS,EAAS,eAAe,EACjD,IAAM,EAAS,EAAc,IAAI;AAEvC,GAAI,QACF,OAAO,EAAI,SAAU,YAAY,EAAI,MAAM,MAAM,CAAC,SAAS,IACvD,EAAI,QACJ,EAAiB;CAEvB,IAAM,IAAS,EAAsB,EAAI,QAAQ;AACjD,CAAI,IACF,EAAI,UAAU,IAEd,OAAO,EAAI;CAGb,IAAM,IAAU,EAAsB,EAAI,SAAS;AAOnD,CANI,IACF,EAAI,WAAW,IAEf,OAAO,EAAI,UAGT,EAAwB,EAAI,IAC9B,EAAI,YAAY,GAChB,EAAI,sBAAsB,GAC1B,OAAO,EAAI,SACX,OAAO,EAAI,aAEX,OAAO,EAAI,WACX,OAAO,EAAI;CAGb,IAAM,IAAY,EAAS,EAAc,WAAW;AAKpD,EAJI,OAAO,KAAK,EAAU,CAAC,WAAW,KAAK,EAAE,gBAAgB,OAC3D,OAAO,EAAc,YAGvB,OAAO,EAAc;AACrB,MAAK,IAAM,KAAO,EAChB,QAAO,EAAc;AAOvB,QAFA,OAAO,EAAc,SAEd;EACL,GAAG;EACH;EACA,eAAe,EAAkB,EAAc;EAC/C,OAAO,EAAc,EAAc;EACpC;;AAGH,SAAS,EACP,GACsB;AACtB,QAAO,EAAW,EAAS,GACvB,EAAgC,EAAS,GACzC,EAAsC,EAAS;;AAGrD,SAAS,EAAoC,GAMb;CAC9B,IAAM,EAAE,aAAU,UAAO,6BAA0B,YAAS,kBAC1D,GACI,IAAuB,EAAS,EAAS,sBAAsB,EAC/D,IAAiB,EAAoB,GAAO,EAAyB;AAwB3E,QAtBA,EAAoC,SACjC,MAAQ,OAAO,EAAqB,GACtC,EAoBM;EAjBL,GAAG;EACH,WAAW;GACT,MAAM;GACN,aAAa,KAAc,GAA0B;GACtD;EACD,GAAI,IAAiB,EAAE,iBAAiB,GAAgB,GAAG,EAAE;EAC7D,GAAI,GAAS,SACT,EACE,SAAS,EAAQ,KAAK,OAAY;GAChC,QAAQ,EAAO;GACf,GAAI,EAAO,MAAM,EAAE,KAAK,EAAO,KAAK,GAAG,EAAE;GACzC,GAAI,EAAO,YAAY,EAAE,WAAW,EAAO,WAAW,GAAG,EAAE;GAC5D,EAAE,EACJ,GACD,EAAE;EAGD;;AAyCT,SAAgB,EACd,GAC0B;CAC1B,IAAM,IAAsB,EAAQ,yBAChC;EAAE,GAAG,EAAQ;EAAU,gBAAgB,EAAQ;EAAwB,GACvE,EAAQ,UAEN,IAAU,EAAW,EAAoB,EACzC,IAAgB,EAA6B,EAAoB,EACjE,IAAe,IACjB,EAAgB,EAAoB,GACpC,KAAA,GAYE,IAAuB,EAVK,EAAQ,gCACtC;EACE,GAAG;EACH,UAAU;GACR,GAAG,EAAQ;GACX,uBAAuB,EAAQ;GAChC;EACF,GACD,EAIH,EAEK,IAAoC;EACxC,gBAAgB;EAChB,WAAW,EAAqB;EAChC,qBACE,EAAkC,EAAqB;EACzD,gBACE,OAAO,EAAqB,kBAAmB,WAC3C,EAAqB,iBACrB;EACN,iBAAiB;EACjB,WAAW;EACX,UAAU,EAAQ,YAAY;EAC/B;AAiBD,CAfI,MACF,EAAQ,OAAO,GAAG,IAAqB,GAAc,GAUnD,EAAQ,oBAAoB,CAAC,MAC/B,EAAQ,oBAAoB,KAG1B,EAAQ,mBACV,EAAQ,kBAAkB,EAAQ;CAGpC,IAAM,IACJ,EAAgC,EAAqB;AAavD,CAZI,MACF,EAAQ,oBAAoB,IAG1B,EAAqB,oBACvB,EAAQ,kBAAkB,EAAqB,kBAG7C,EAAqB,YACvB,EAAQ,UAAU,EAAqB,UAGrC,EAAqB,gBACvB,EAAQ,cAAc,EAAqB;CAG7C,IAAM,IAA8C,EAAE,EAChD,IAAoB,EAA2B,EAAoB;AA0BzE,KAzBI,MACF,EAAoB,KAAuB,IAE7C,OAAO,OACL,GACC,EAAqB,yBAEJ,EAAE,CACrB,EACI,KACH,OAAO,EAAoB,IAEzB,OAAO,KAAK,EAAoB,CAAC,SAAS,MAC5C,EAAQ,wBAAwB,IAG9B,EAAqB,sBACvB,EAAQ,oBAAoB,EAAqB,oBAQ/C,EAAQ,iBAAiB,EAAQ,cAAc,SAAS,GAAG;EAC7D,IAAM,IAAU,GAA0B,EACpC,IAAU,IAAU,EAAiB,EAAQ,GAAG,EAAE,EAElD,IAAwC,EAAE;AAChD,OAAK,IAAM,KAAU,EAAQ,eAAe;GAC1C,IAAM,IAA6B;IACjC,MAAM;IACN,KAAK,yBAAyB,mBAAmB,EAAO,KAAK;IAC7D,aAAa,EAAO;IACrB;AAMD,GAJI,OAAO,KAAK,EAAQ,CAAC,SAAS,MAChC,EAAa,UAAU,IAGzB,EAAQ,EAAO,QAAQ;;AAGzB,IAAQ,UAAU;;AAGpB,QAAO;;AAGT,IAAa,IACX;AAQF,eAAsB,EACpB,GACe;AAEV,OADO,EAAS,EAAc,IACN,CAAI,IAG7B,EAAC,MADgB,EAAuB,iBAAiB,EACjD,UACV,OAAU,MAAM,EAAkC;;AAItD,eAAsB,EAAmD,GAQpC;CACnC,IAAM,EAAE,sBAAmB,MAAM,OAAO,yBAElC,CAAC,GAAgB,KAAiB,MAAM,QAAQ,IAAI,CACxD,EAAgB,4BAA4B,EAC5C,EAAe,YAAY,CAC5B,CAAC,EAEI,EAAE,kBAAe,yBAAsB,wBAC3C;AAIF,QAFA,MAAM,EAA4B,EAAc,EAEzC,EAA8B;EACnC,GAAG;EACH,wBAAwB;EACxB,+BAA+B;EAC/B;EACA;EACD,CAAC;;AAGJ,SAAgB,KAAuC;AACrD,QAAO,EAAE,OAAO,EAAE,EAAE"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/@openhands/typescript-client/dist/client/server-client.cjs`),t=require(`../node_modules/@openhands/typescript-client/dist/client/settings-client.cjs`),n=require(`./agent-server-config.cjs`),r=require(`./backend-registry/active-store.cjs`),i=require(`./agent-server-client-options.cjs`);var a=5e3,o=null,s=e=>Array.isArray(e?.usable_tools)?e.usable_tools:null,c=class extends Error{details;noBackendConfigured;constructor(e,t){let n=t?.noBackendConfigured??!1;super(n?`No agent server backend is configured yet. Add a backend to get started.`:`Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page.`),this.name=`AgentServerUnavailableError`,this.details=e??null,this.noBackendConfigured=n}},l=e=>e instanceof c||typeof e==`object`&&!!e&&`name`in e&&e.name===`AgentServerUnavailableError`,u=e=>n.isAuthRequired()&&m(e,401);function d(){o=null}function f(e){let t=s(o);return Array.isArray(t)?t.includes(e):!0}function p(e){return e instanceof Error&&e.name===`HttpError`&&`status`in e&&typeof e.status==`number`}function m(e,t){return p(e)&&e.status===t}async function h(){let s=r.getEffectiveLocalBackend();if(!s){if(d(),r.isNoBackend(r.getActiveBackend().backend))throw new c(`No backend configured`,{noBackendConfigured:!0});return null}let l=i.getAgentServerClientOptions({host:s.host,sessionApiKey:s.apiKey||null,timeout:a}),u;try{u=await new e.ServerClient(l).getServerInfo()}catch(e){throw d(),m(e,401)?e:new c(e instanceof Error?e.message:null)}if(n.isAuthRequired())try{await new t.SettingsClient(l).getSettings()}catch(e){if(m(e,401))throw e;console.warn(`[agent-server] getSettings() probe failed (non-401):`,e)}return o=u,u}exports.clearCachedAgentServerInfo=d,exports.isAgentServerAuthError=u,exports.isAgentServerToolAvailable=f,exports.isAgentServerUnavailableError=l,exports.isSdkHttpStatusError=m,exports.loadAgentServerInfo=h;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../node_modules/@openhands/typescript-client/dist/client/server-client.cjs`),t=require(`../node_modules/@openhands/typescript-client/dist/client/settings-client.cjs`),n=require(`./agent-server-config.cjs`),r=require(`./backend-registry/active-store.cjs`),i=require(`./agent-server-client-options.cjs`),a=require(`../config/defaults.cjs`);var o=5e3,s=`unknown`,c=a.default.compatibility.minimumAgentServer,l=`AGENT_SERVER_UNSUPPORTED_VERSION`,u=null,d=e=>Array.isArray(e?.usable_tools)?e.usable_tools:null,f=class extends Error{details;noBackendConfigured;constructor(e,t){let n=t?.noBackendConfigured??!1;super(n?`No agent server backend is configured yet. Add a backend to get started.`:`Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page.`),this.name=`AgentServerUnavailableError`,this.details=e??null,this.noBackendConfigured=n}},p=e=>e instanceof f||typeof e==`object`&&!!e&&`name`in e&&e.name===`AgentServerUnavailableError`,m=class extends f{code=l;actualVersion;requiredVersion=c;constructor(e){let t=`Agent Canvas requires agent-server ${c} or newer; this backend is running ${e}. Please upgrade the agent-server backend.`;super(t),this.name=`AgentServerUnsupportedVersionError`,this.message=t,this.actualVersion=e}},h=e=>n.isAuthRequired()&&y(e,401);function g(){u=null}function _(e){let t=d(u);return Array.isArray(t)?t.includes(e):!0}function v(e){return e instanceof Error&&e.name===`HttpError`&&`status`in e&&typeof e.status==`number`}function y(e,t){return v(e)&&e.status===t}function b(e){return typeof e.version==`string`&&e.version.trim()?e.version.trim():s}function x(e,t){let n=S(e),r=S(t);if(!n||!r)return null;for(let e of[`major`,`minor`,`patch`]){if(n[e]>r[e])return 1;if(n[e]<r[e])return-1}return n.prerelease&&!r.prerelease?-1:!n.prerelease&&r.prerelease?1:n.prerelease&&r.prerelease?n.prerelease.localeCompare(r.prerelease):0}function S(e){let[t]=e.trim().replace(/^v/,``).split(`+`),[n,r]=t.split(`-`,2),i=n.split(`.`);if(i.length!==3)return null;let[a,o,s]=i.map(e=>Number(e));return[a,o,s].every(e=>Number.isInteger(e)&&e>=0)?{major:a,minor:o,patch:s,prerelease:r}:null}function C(e){let t=b(e),n=x(t,c);if(n===null||n<0)throw g(),new m(t)}async function w(){let a=r.getEffectiveLocalBackend();if(!a){if(g(),r.isNoBackend(r.getActiveBackend().backend))throw new f(`No backend configured`,{noBackendConfigured:!0});return null}let s=i.getAgentServerClientOptions({host:a.host,sessionApiKey:a.apiKey||null,timeout:o}),c;try{c=await new e.ServerClient(s).getServerInfo()}catch(e){throw g(),y(e,401)?e:new f(e instanceof Error?e.message:null)}if(C(c),n.isAuthRequired())try{await new t.SettingsClient(s).getSettings()}catch(e){if(y(e,401))throw e;console.warn(`[agent-server] getSettings() probe failed (non-401):`,e)}return u=c,c}exports.assertAgentServerVersionIsSupported=C,exports.clearCachedAgentServerInfo=g,exports.isAgentServerAuthError=h,exports.isAgentServerToolAvailable=_,exports.isAgentServerUnavailableError=p,exports.isSdkHttpStatusError=y,exports.loadAgentServerInfo=w;
2
2
  //# sourceMappingURL=agent-server-compatibility.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-server-compatibility.cjs","names":[],"sources":["../../src/api/agent-server-compatibility.ts"],"sourcesContent":["import {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport type { ServerInfo as BaseServerInfo } from \"@openhands/typescript-client\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { isAuthRequired } from \"#/api/agent-server-config\";\nimport {\n getActiveBackend,\n getEffectiveLocalBackend,\n isNoBackend,\n} from \"#/api/backend-registry/active-store\";\n\nconst AGENT_SERVER_INFO_TIMEOUT_MS = 5000;\n\nexport interface AgentServerInfo extends BaseServerInfo {\n usable_tools?: string[] | null;\n}\n\nlet cachedAgentServerInfo: AgentServerInfo | null = null;\n\nconst getAdvertisedTools = (serverInfo: AgentServerInfo | null) => {\n if (Array.isArray(serverInfo?.usable_tools)) {\n return serverInfo.usable_tools;\n }\n return null;\n};\n\nexport class AgentServerUnavailableError extends Error {\n readonly details: string | null;\n readonly noBackendConfigured: boolean;\n\n constructor(\n details?: string | null,\n options?: { noBackendConfigured?: boolean },\n ) {\n const noBackendConfigured = options?.noBackendConfigured ?? false;\n super(\n noBackendConfigured\n ? \"No agent server backend is configured yet. Add a backend to get started.\"\n : \"Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page.\",\n );\n this.name = \"AgentServerUnavailableError\";\n this.details = details ?? null;\n this.noBackendConfigured = noBackendConfigured;\n }\n}\n\nexport const isAgentServerUnavailableError = (\n error: unknown,\n): error is AgentServerUnavailableError =>\n error instanceof AgentServerUnavailableError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"AgentServerUnavailableError\");\n\n/**\n * Returns true when the agent-server probe failed with HTTP 401.\n * In public mode this means the stored key is stale (server restarted\n * with a different `LOCAL_BACKEND_API_KEY`). Only meaningful when\n * auth is required — a 401 in local mode is a misconfiguration, not a\n * key-rotation event. Uses {@link isAuthRequired} so both the build-time\n * `VITE_AUTH_REQUIRED` flag and the runtime `window.__AGENT_CANVAS_AUTH_REQUIRED__`\n * injection (used by pre-built static binaries) are honoured.\n */\nexport const isAgentServerAuthError = (error: unknown): boolean =>\n isAuthRequired() && isSdkHttpStatusError(error, 401);\n\nexport function clearCachedAgentServerInfo() {\n cachedAgentServerInfo = null;\n}\n\nexport function isAgentServerToolAvailable(toolName: string) {\n const availableTools = getAdvertisedTools(cachedAgentServerInfo);\n if (!Array.isArray(availableTools)) {\n return true;\n }\n return availableTools.includes(toolName);\n}\n\nexport function isSdkHttpError(error: unknown) {\n return (\n error instanceof Error &&\n error.name === \"HttpError\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n}\n\n/**\n * Narrows an SDK HTTP error to a specific status code.\n * Use instead of manually casting `(err as { status: number }).status`.\n */\nexport function isSdkHttpStatusError(error: unknown, status: number): boolean {\n return (\n isSdkHttpError(error) && (error as { status: number }).status === status\n );\n}\n\nexport async function loadAgentServerInfo() {\n // The probe is a *local* agent-server concern — it verifies the runtime\n // hosting the GUI is reachable. It must NEVER run against the active\n // backend when that backend is cloud, because cloud hosts don't\n // expose /api/server_info and would fail with a CORS error besides.\n const local = getEffectiveLocalBackend();\n if (!local) {\n clearCachedAgentServerInfo();\n\n // Empty registry (NO_BACKEND sentinel) — the user has no backend\n // configured at all. Throw so root.tsx shows the manage-backends\n // modal instead of silently rendering a broken home page.\n if (isNoBackend(getActiveBackend().backend)) {\n throw new AgentServerUnavailableError(\"No backend configured\", {\n noBackendConfigured: true,\n });\n }\n\n // Active backend is cloud — no local probe needed.\n return null;\n }\n\n const clientOptions = getAgentServerClientOptions({\n host: local.host,\n sessionApiKey: local.apiKey || null,\n timeout: AGENT_SERVER_INFO_TIMEOUT_MS,\n });\n let serverInfo: AgentServerInfo;\n\n try {\n serverInfo = (await new ServerClient(\n clientOptions,\n ).getServerInfo()) as AgentServerInfo;\n } catch (error) {\n clearCachedAgentServerInfo();\n // Preserve 401 so root.tsx can show the auth screen (public mode).\n // All other HTTP errors (502, 503, etc.) mean the server is unreachable\n // or misconfigured — treat them as unavailable.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n const details = error instanceof Error ? error.message : null;\n throw new AgentServerUnavailableError(details);\n }\n\n // /server_info is unprotected, so a stale session key still gets 200.\n // In public mode, validate the key against a protected endpoint so a\n // server restart with a new LOCAL_BACKEND_API_KEY surfaces immediately\n // instead of letting the app load and fail on every subsequent call.\n if (isAuthRequired()) {\n try {\n await new SettingsClient(clientOptions).getSettings();\n } catch (error) {\n // Only rethrow 401 — that means the stored key is invalid /\n // rotated. Other HTTP errors (403, 5xx) and non-HTTP errors\n // (network, timeout) are swallowed: the server *is* up (we just\n // reached /server_info), so let the app proceed with an\n // unvalidated key rather than blocking the UI.\n // NOTE: If the connection drops between the /server_info and\n // getSettings() probes, the app loads with an unvalidated key and\n // subsequent 401s won't trigger the auth screen (they come from\n // React Query hooks, not this bootstrap path). Acceptable for now\n // since the window is narrow and a page refresh recovers.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n console.warn(\n \"[agent-server] getSettings() probe failed (non-401):\",\n error,\n );\n }\n }\n\n cachedAgentServerInfo = serverInfo;\n return serverInfo;\n}\n"],"mappings":"4WAaA,IAAM,EAA+B,IAMjC,EAAgD,KAE9C,EAAsB,GACtB,MAAM,QAAQ,GAAY,aAAa,CAClC,EAAW,aAEb,KAGI,EAAb,cAAiD,KAAM,CACrD,QACA,oBAEA,YACE,EACA,EACA,CACA,IAAM,EAAsB,GAAS,qBAAuB,GAC5D,MACE,EACI,2EACA,iHACL,CACD,KAAK,KAAO,8BACZ,KAAK,QAAU,GAAW,KAC1B,KAAK,oBAAsB,IAIlB,EACX,GAEA,aAAiB,GAChB,OAAO,GAAU,YAChB,GACA,SAAU,GACV,EAAM,OAAS,8BAWN,EAA0B,GACrC,EAAA,gBAAgB,EAAI,EAAqB,EAAO,IAAI,CAEtD,SAAgB,GAA6B,CAC3C,EAAwB,KAG1B,SAAgB,EAA2B,EAAkB,CAC3D,IAAM,EAAiB,EAAmB,EAAsB,CAIhE,OAHK,MAAM,QAAQ,EAAe,CAG3B,EAAe,SAAS,EAAS,CAF/B,GAKX,SAAgB,EAAe,EAAgB,CAC7C,OACE,aAAiB,OACjB,EAAM,OAAS,aACf,WAAY,GACZ,OAAO,EAAM,QAAW,SAQ5B,SAAgB,EAAqB,EAAgB,EAAyB,CAC5E,OACE,EAAe,EAAM,EAAK,EAA6B,SAAW,EAItE,eAAsB,GAAsB,CAK1C,IAAM,EAAQ,EAAA,0BAA0B,CACxC,GAAI,CAAC,EAAO,CAMV,GALA,GAA4B,CAKxB,EAAA,YAAY,EAAA,kBAAkB,CAAC,QAAQ,CACzC,MAAM,IAAI,EAA4B,wBAAyB,CAC7D,oBAAqB,GACtB,CAAC,CAIJ,OAAO,KAGT,IAAM,EAAgB,EAAA,4BAA4B,CAChD,KAAM,EAAM,KACZ,cAAe,EAAM,QAAU,KAC/B,QAAS,EACV,CAAC,CACE,EAEJ,GAAI,CACF,EAAc,MAAM,IAAI,EAAA,aACtB,EACD,CAAC,eAAe,OACV,EAAO,CAUd,MATA,GAA4B,CAIxB,EAAqB,EAAO,IAAI,CAC5B,EAIF,IAAI,EADM,aAAiB,MAAQ,EAAM,QAAU,KACX,CAOhD,GAAI,EAAA,gBAAgB,CAClB,GAAI,CACF,MAAM,IAAI,EAAA,eAAe,EAAc,CAAC,aAAa,OAC9C,EAAO,CAWd,GAAI,EAAqB,EAAO,IAAI,CAClC,MAAM,EAGR,QAAQ,KACN,uDACA,EACD,CAKL,MADA,GAAwB,EACjB"}
1
+ {"version":3,"file":"agent-server-compatibility.cjs","names":[],"sources":["../../src/api/agent-server-compatibility.ts"],"sourcesContent":["import {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport type { ServerInfo as BaseServerInfo } from \"@openhands/typescript-client\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { isAuthRequired } from \"#/api/agent-server-config\";\nimport {\n getActiveBackend,\n getEffectiveLocalBackend,\n isNoBackend,\n} from \"#/api/backend-registry/active-store\";\nimport defaults from \"../../config/defaults.json\";\n\nconst AGENT_SERVER_INFO_TIMEOUT_MS = 5000;\nconst UNKNOWN_AGENT_SERVER_VERSION = \"unknown\";\n\nexport const MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION =\n defaults.compatibility.minimumAgentServer;\nexport const AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE =\n \"AGENT_SERVER_UNSUPPORTED_VERSION\";\n\nexport interface AgentServerInfo extends BaseServerInfo {\n usable_tools?: string[] | null;\n}\n\nlet cachedAgentServerInfo: AgentServerInfo | null = null;\n\nconst getAdvertisedTools = (serverInfo: AgentServerInfo | null) => {\n if (Array.isArray(serverInfo?.usable_tools)) {\n return serverInfo.usable_tools;\n }\n return null;\n};\n\nexport class AgentServerUnavailableError extends Error {\n readonly details: string | null;\n readonly noBackendConfigured: boolean;\n\n constructor(\n details?: string | null,\n options?: { noBackendConfigured?: boolean },\n ) {\n const noBackendConfigured = options?.noBackendConfigured ?? false;\n super(\n noBackendConfigured\n ? \"No agent server backend is configured yet. Add a backend to get started.\"\n : \"Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page.\",\n );\n this.name = \"AgentServerUnavailableError\";\n this.details = details ?? null;\n this.noBackendConfigured = noBackendConfigured;\n }\n}\n\nexport const isAgentServerUnavailableError = (\n error: unknown,\n): error is AgentServerUnavailableError =>\n error instanceof AgentServerUnavailableError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"AgentServerUnavailableError\");\n\nexport class AgentServerUnsupportedVersionError extends AgentServerUnavailableError {\n readonly code = AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE;\n readonly actualVersion: string;\n readonly requiredVersion = MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION;\n\n constructor(actualVersion: string) {\n const message = `Agent Canvas requires agent-server ${MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION} or newer; this backend is running ${actualVersion}. Please upgrade the agent-server backend.`;\n super(message);\n this.name = \"AgentServerUnsupportedVersionError\";\n this.message = message;\n this.actualVersion = actualVersion;\n }\n}\n\nexport const isAgentServerUnsupportedVersionError = (\n error: unknown,\n): error is AgentServerUnsupportedVersionError =>\n error instanceof AgentServerUnsupportedVersionError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE);\n\n/**\n * Returns true when the agent-server probe failed with HTTP 401.\n * In public mode this means the stored key is stale (server restarted\n * with a different `LOCAL_BACKEND_API_KEY`). Only meaningful when\n * auth is required — a 401 in local mode is a misconfiguration, not a\n * key-rotation event. Uses {@link isAuthRequired} so both the build-time\n * `VITE_AUTH_REQUIRED` flag and the runtime `window.__AGENT_CANVAS_AUTH_REQUIRED__`\n * injection (used by pre-built static binaries) are honoured.\n */\nexport const isAgentServerAuthError = (error: unknown): boolean =>\n isAuthRequired() && isSdkHttpStatusError(error, 401);\n\nexport function clearCachedAgentServerInfo() {\n cachedAgentServerInfo = null;\n}\n\nexport function isAgentServerToolAvailable(toolName: string) {\n const availableTools = getAdvertisedTools(cachedAgentServerInfo);\n if (!Array.isArray(availableTools)) {\n return true;\n }\n return availableTools.includes(toolName);\n}\n\nexport function isSdkHttpError(error: unknown) {\n return (\n error instanceof Error &&\n error.name === \"HttpError\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n}\n\n/**\n * Narrows an SDK HTTP error to a specific status code.\n * Use instead of manually casting `(err as { status: number }).status`.\n */\nexport function isSdkHttpStatusError(error: unknown, status: number): boolean {\n return (\n isSdkHttpError(error) && (error as { status: number }).status === status\n );\n}\n\nfunction getReportedAgentServerVersion(serverInfo: AgentServerInfo) {\n return typeof serverInfo.version === \"string\" && serverInfo.version.trim()\n ? serverInfo.version.trim()\n : UNKNOWN_AGENT_SERVER_VERSION;\n}\n\nfunction compareAgentServerVersions(actual: string, required: string) {\n const parsedActual = parseAgentServerVersion(actual);\n const parsedRequired = parseAgentServerVersion(required);\n\n if (!parsedActual || !parsedRequired) {\n return null;\n }\n\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (parsedActual[key] > parsedRequired[key]) {\n return 1;\n }\n if (parsedActual[key] < parsedRequired[key]) {\n return -1;\n }\n }\n\n if (parsedActual.prerelease && !parsedRequired.prerelease) {\n return -1;\n }\n if (!parsedActual.prerelease && parsedRequired.prerelease) {\n return 1;\n }\n if (parsedActual.prerelease && parsedRequired.prerelease) {\n return parsedActual.prerelease.localeCompare(parsedRequired.prerelease);\n }\n\n return 0;\n}\n\nfunction parseAgentServerVersion(version: string) {\n const trimmed = version.trim().replace(/^v/, \"\");\n const [withoutBuild] = trimmed.split(\"+\");\n const [core, prerelease] = withoutBuild.split(\"-\", 2);\n const parts = core.split(\".\");\n\n if (parts.length !== 3) {\n return null;\n }\n\n const [major, minor, patch] = parts.map((part) => Number(part));\n if (\n ![major, minor, patch].every((part) => Number.isInteger(part) && part >= 0)\n ) {\n return null;\n }\n\n return { major, minor, patch, prerelease };\n}\n\nexport function assertAgentServerVersionIsSupported(\n serverInfo: AgentServerInfo,\n) {\n const actualVersion = getReportedAgentServerVersion(serverInfo);\n const comparison = compareAgentServerVersions(\n actualVersion,\n MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION,\n );\n\n if (comparison === null || comparison < 0) {\n clearCachedAgentServerInfo();\n throw new AgentServerUnsupportedVersionError(actualVersion);\n }\n}\n\nexport async function loadAgentServerInfo() {\n // The probe is a *local* agent-server concern — it verifies the runtime\n // hosting the GUI is reachable. It must NEVER run against the active\n // backend when that backend is cloud, because cloud hosts don't\n // expose /api/server_info and would fail with a CORS error besides.\n const local = getEffectiveLocalBackend();\n if (!local) {\n clearCachedAgentServerInfo();\n\n // Empty registry (NO_BACKEND sentinel) — the user has no backend\n // configured at all. Throw so root.tsx shows the manage-backends\n // modal instead of silently rendering a broken home page.\n if (isNoBackend(getActiveBackend().backend)) {\n throw new AgentServerUnavailableError(\"No backend configured\", {\n noBackendConfigured: true,\n });\n }\n\n // Active backend is cloud — no local probe needed.\n return null;\n }\n\n const clientOptions = getAgentServerClientOptions({\n host: local.host,\n sessionApiKey: local.apiKey || null,\n timeout: AGENT_SERVER_INFO_TIMEOUT_MS,\n });\n let serverInfo: AgentServerInfo;\n\n try {\n serverInfo = (await new ServerClient(\n clientOptions,\n ).getServerInfo()) as AgentServerInfo;\n } catch (error) {\n clearCachedAgentServerInfo();\n // Preserve 401 so root.tsx can show the auth screen (public mode).\n // All other HTTP errors (502, 503, etc.) mean the server is unreachable\n // or misconfigured — treat them as unavailable.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n const details = error instanceof Error ? error.message : null;\n throw new AgentServerUnavailableError(details);\n }\n\n assertAgentServerVersionIsSupported(serverInfo);\n\n // /server_info is unprotected, so a stale session key still gets 200.\n // In public mode, validate the key against a protected endpoint so a\n // server restart with a new LOCAL_BACKEND_API_KEY surfaces immediately\n // instead of letting the app load and fail on every subsequent call.\n if (isAuthRequired()) {\n try {\n await new SettingsClient(clientOptions).getSettings();\n } catch (error) {\n // Only rethrow 401 — that means the stored key is invalid /\n // rotated. Other HTTP errors (403, 5xx) and non-HTTP errors\n // (network, timeout) are swallowed: the server *is* up (we just\n // reached /server_info), so let the app proceed with an\n // unvalidated key rather than blocking the UI.\n // NOTE: If the connection drops between the /server_info and\n // getSettings() probes, the app loads with an unvalidated key and\n // subsequent 401s won't trigger the auth screen (they come from\n // React Query hooks, not this bootstrap path). Acceptable for now\n // since the window is narrow and a page refresh recovers.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n console.warn(\n \"[agent-server] getSettings() probe failed (non-401):\",\n error,\n );\n }\n }\n\n cachedAgentServerInfo = serverInfo;\n return serverInfo;\n}\n"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import type { ServerInfo as BaseServerInfo } from "@openhands/typescript-client";
2
+ export declare const MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION: string;
3
+ export declare const AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE = "AGENT_SERVER_UNSUPPORTED_VERSION";
2
4
  export interface AgentServerInfo extends BaseServerInfo {
3
5
  usable_tools?: string[] | null;
4
6
  }
@@ -10,6 +12,13 @@ export declare class AgentServerUnavailableError extends Error {
10
12
  });
11
13
  }
12
14
  export declare const isAgentServerUnavailableError: (error: unknown) => error is AgentServerUnavailableError;
15
+ export declare class AgentServerUnsupportedVersionError extends AgentServerUnavailableError {
16
+ readonly code = "AGENT_SERVER_UNSUPPORTED_VERSION";
17
+ readonly actualVersion: string;
18
+ readonly requiredVersion: string;
19
+ constructor(actualVersion: string);
20
+ }
21
+ export declare const isAgentServerUnsupportedVersionError: (error: unknown) => error is AgentServerUnsupportedVersionError;
13
22
  /**
14
23
  * Returns true when the agent-server probe failed with HTTP 401.
15
24
  * In public mode this means the stored key is stale (server restarted
@@ -28,4 +37,5 @@ export declare function isSdkHttpError(error: unknown): boolean;
28
37
  * Use instead of manually casting `(err as { status: number }).status`.
29
38
  */
30
39
  export declare function isSdkHttpStatusError(error: unknown, status: number): boolean;
40
+ export declare function assertAgentServerVersionIsSupported(serverInfo: AgentServerInfo): void;
31
41
  export declare function loadAgentServerInfo(): Promise<AgentServerInfo | null>;
@@ -3,53 +3,97 @@ import { SettingsClient as t } from "../node_modules/@openhands/typescript-clien
3
3
  import { isAuthRequired as n } from "./agent-server-config.js";
4
4
  import { getActiveBackend as r, getEffectiveLocalBackend as i, isNoBackend as a } from "./backend-registry/active-store.js";
5
5
  import { getAgentServerClientOptions as o } from "./agent-server-client-options.js";
6
+ import s from "../config/defaults.js";
6
7
  //#region src/api/agent-server-compatibility.ts
7
- var s = 5e3, c = null, l = (e) => Array.isArray(e?.usable_tools) ? e.usable_tools : null, u = class extends Error {
8
+ var c = 5e3, l = "unknown", u = s.compatibility.minimumAgentServer, d = "AGENT_SERVER_UNSUPPORTED_VERSION", f = null, p = (e) => Array.isArray(e?.usable_tools) ? e.usable_tools : null, m = class extends Error {
8
9
  details;
9
10
  noBackendConfigured;
10
11
  constructor(e, t) {
11
12
  let n = t?.noBackendConfigured ?? !1;
12
13
  super(n ? "No agent server backend is configured yet. Add a backend to get started." : "Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page."), this.name = "AgentServerUnavailableError", this.details = e ?? null, this.noBackendConfigured = n;
13
14
  }
14
- }, d = (e) => e instanceof u || typeof e == "object" && !!e && "name" in e && e.name === "AgentServerUnavailableError", f = (e) => n() && g(e, 401);
15
- function p() {
16
- c = null;
15
+ }, h = (e) => e instanceof m || typeof e == "object" && !!e && "name" in e && e.name === "AgentServerUnavailableError", g = class extends m {
16
+ code = d;
17
+ actualVersion;
18
+ requiredVersion = u;
19
+ constructor(e) {
20
+ let t = `Agent Canvas requires agent-server ${u} or newer; this backend is running ${e}. Please upgrade the agent-server backend.`;
21
+ super(t), this.name = "AgentServerUnsupportedVersionError", this.message = t, this.actualVersion = e;
22
+ }
23
+ }, _ = (e) => n() && x(e, 401);
24
+ function v() {
25
+ f = null;
17
26
  }
18
- function m(e) {
19
- let t = l(c);
27
+ function y(e) {
28
+ let t = p(f);
20
29
  return Array.isArray(t) ? t.includes(e) : !0;
21
30
  }
22
- function h(e) {
31
+ function b(e) {
23
32
  return e instanceof Error && e.name === "HttpError" && "status" in e && typeof e.status == "number";
24
33
  }
25
- function g(e, t) {
26
- return h(e) && e.status === t;
34
+ function x(e, t) {
35
+ return b(e) && e.status === t;
36
+ }
37
+ function S(e) {
38
+ return typeof e.version == "string" && e.version.trim() ? e.version.trim() : l;
39
+ }
40
+ function C(e, t) {
41
+ let n = w(e), r = w(t);
42
+ if (!n || !r) return null;
43
+ for (let e of [
44
+ "major",
45
+ "minor",
46
+ "patch"
47
+ ]) {
48
+ if (n[e] > r[e]) return 1;
49
+ if (n[e] < r[e]) return -1;
50
+ }
51
+ return n.prerelease && !r.prerelease ? -1 : !n.prerelease && r.prerelease ? 1 : n.prerelease && r.prerelease ? n.prerelease.localeCompare(r.prerelease) : 0;
52
+ }
53
+ function w(e) {
54
+ let [t] = e.trim().replace(/^v/, "").split("+"), [n, r] = t.split("-", 2), i = n.split(".");
55
+ if (i.length !== 3) return null;
56
+ let [a, o, s] = i.map((e) => Number(e));
57
+ return [
58
+ a,
59
+ o,
60
+ s
61
+ ].every((e) => Number.isInteger(e) && e >= 0) ? {
62
+ major: a,
63
+ minor: o,
64
+ patch: s,
65
+ prerelease: r
66
+ } : null;
67
+ }
68
+ function T(e) {
69
+ let t = S(e), n = C(t, u);
70
+ if (n === null || n < 0) throw v(), new g(t);
27
71
  }
28
- async function _() {
29
- let l = i();
30
- if (!l) {
31
- if (p(), a(r().backend)) throw new u("No backend configured", { noBackendConfigured: !0 });
72
+ async function E() {
73
+ let s = i();
74
+ if (!s) {
75
+ if (v(), a(r().backend)) throw new m("No backend configured", { noBackendConfigured: !0 });
32
76
  return null;
33
77
  }
34
- let d = o({
35
- host: l.host,
36
- sessionApiKey: l.apiKey || null,
37
- timeout: s
38
- }), f;
78
+ let l = o({
79
+ host: s.host,
80
+ sessionApiKey: s.apiKey || null,
81
+ timeout: c
82
+ }), u;
39
83
  try {
40
- f = await new e(d).getServerInfo();
84
+ u = await new e(l).getServerInfo();
41
85
  } catch (e) {
42
- throw p(), g(e, 401) ? e : new u(e instanceof Error ? e.message : null);
86
+ throw v(), x(e, 401) ? e : new m(e instanceof Error ? e.message : null);
43
87
  }
44
- if (n()) try {
45
- await new t(d).getSettings();
88
+ if (T(u), n()) try {
89
+ await new t(l).getSettings();
46
90
  } catch (e) {
47
- if (g(e, 401)) throw e;
91
+ if (x(e, 401)) throw e;
48
92
  console.warn("[agent-server] getSettings() probe failed (non-401):", e);
49
93
  }
50
- return c = f, f;
94
+ return f = u, u;
51
95
  }
52
96
  //#endregion
53
- export { p as clearCachedAgentServerInfo, f as isAgentServerAuthError, m as isAgentServerToolAvailable, d as isAgentServerUnavailableError, g as isSdkHttpStatusError, _ as loadAgentServerInfo };
97
+ export { T as assertAgentServerVersionIsSupported, v as clearCachedAgentServerInfo, _ as isAgentServerAuthError, y as isAgentServerToolAvailable, h as isAgentServerUnavailableError, x as isSdkHttpStatusError, E as loadAgentServerInfo };
54
98
 
55
99
  //# sourceMappingURL=agent-server-compatibility.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-server-compatibility.js","names":[],"sources":["../../src/api/agent-server-compatibility.ts"],"sourcesContent":["import {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport type { ServerInfo as BaseServerInfo } from \"@openhands/typescript-client\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { isAuthRequired } from \"#/api/agent-server-config\";\nimport {\n getActiveBackend,\n getEffectiveLocalBackend,\n isNoBackend,\n} from \"#/api/backend-registry/active-store\";\n\nconst AGENT_SERVER_INFO_TIMEOUT_MS = 5000;\n\nexport interface AgentServerInfo extends BaseServerInfo {\n usable_tools?: string[] | null;\n}\n\nlet cachedAgentServerInfo: AgentServerInfo | null = null;\n\nconst getAdvertisedTools = (serverInfo: AgentServerInfo | null) => {\n if (Array.isArray(serverInfo?.usable_tools)) {\n return serverInfo.usable_tools;\n }\n return null;\n};\n\nexport class AgentServerUnavailableError extends Error {\n readonly details: string | null;\n readonly noBackendConfigured: boolean;\n\n constructor(\n details?: string | null,\n options?: { noBackendConfigured?: boolean },\n ) {\n const noBackendConfigured = options?.noBackendConfigured ?? false;\n super(\n noBackendConfigured\n ? \"No agent server backend is configured yet. Add a backend to get started.\"\n : \"Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page.\",\n );\n this.name = \"AgentServerUnavailableError\";\n this.details = details ?? null;\n this.noBackendConfigured = noBackendConfigured;\n }\n}\n\nexport const isAgentServerUnavailableError = (\n error: unknown,\n): error is AgentServerUnavailableError =>\n error instanceof AgentServerUnavailableError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"AgentServerUnavailableError\");\n\n/**\n * Returns true when the agent-server probe failed with HTTP 401.\n * In public mode this means the stored key is stale (server restarted\n * with a different `LOCAL_BACKEND_API_KEY`). Only meaningful when\n * auth is required — a 401 in local mode is a misconfiguration, not a\n * key-rotation event. Uses {@link isAuthRequired} so both the build-time\n * `VITE_AUTH_REQUIRED` flag and the runtime `window.__AGENT_CANVAS_AUTH_REQUIRED__`\n * injection (used by pre-built static binaries) are honoured.\n */\nexport const isAgentServerAuthError = (error: unknown): boolean =>\n isAuthRequired() && isSdkHttpStatusError(error, 401);\n\nexport function clearCachedAgentServerInfo() {\n cachedAgentServerInfo = null;\n}\n\nexport function isAgentServerToolAvailable(toolName: string) {\n const availableTools = getAdvertisedTools(cachedAgentServerInfo);\n if (!Array.isArray(availableTools)) {\n return true;\n }\n return availableTools.includes(toolName);\n}\n\nexport function isSdkHttpError(error: unknown) {\n return (\n error instanceof Error &&\n error.name === \"HttpError\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n}\n\n/**\n * Narrows an SDK HTTP error to a specific status code.\n * Use instead of manually casting `(err as { status: number }).status`.\n */\nexport function isSdkHttpStatusError(error: unknown, status: number): boolean {\n return (\n isSdkHttpError(error) && (error as { status: number }).status === status\n );\n}\n\nexport async function loadAgentServerInfo() {\n // The probe is a *local* agent-server concern — it verifies the runtime\n // hosting the GUI is reachable. It must NEVER run against the active\n // backend when that backend is cloud, because cloud hosts don't\n // expose /api/server_info and would fail with a CORS error besides.\n const local = getEffectiveLocalBackend();\n if (!local) {\n clearCachedAgentServerInfo();\n\n // Empty registry (NO_BACKEND sentinel) — the user has no backend\n // configured at all. Throw so root.tsx shows the manage-backends\n // modal instead of silently rendering a broken home page.\n if (isNoBackend(getActiveBackend().backend)) {\n throw new AgentServerUnavailableError(\"No backend configured\", {\n noBackendConfigured: true,\n });\n }\n\n // Active backend is cloud — no local probe needed.\n return null;\n }\n\n const clientOptions = getAgentServerClientOptions({\n host: local.host,\n sessionApiKey: local.apiKey || null,\n timeout: AGENT_SERVER_INFO_TIMEOUT_MS,\n });\n let serverInfo: AgentServerInfo;\n\n try {\n serverInfo = (await new ServerClient(\n clientOptions,\n ).getServerInfo()) as AgentServerInfo;\n } catch (error) {\n clearCachedAgentServerInfo();\n // Preserve 401 so root.tsx can show the auth screen (public mode).\n // All other HTTP errors (502, 503, etc.) mean the server is unreachable\n // or misconfigured — treat them as unavailable.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n const details = error instanceof Error ? error.message : null;\n throw new AgentServerUnavailableError(details);\n }\n\n // /server_info is unprotected, so a stale session key still gets 200.\n // In public mode, validate the key against a protected endpoint so a\n // server restart with a new LOCAL_BACKEND_API_KEY surfaces immediately\n // instead of letting the app load and fail on every subsequent call.\n if (isAuthRequired()) {\n try {\n await new SettingsClient(clientOptions).getSettings();\n } catch (error) {\n // Only rethrow 401 — that means the stored key is invalid /\n // rotated. Other HTTP errors (403, 5xx) and non-HTTP errors\n // (network, timeout) are swallowed: the server *is* up (we just\n // reached /server_info), so let the app proceed with an\n // unvalidated key rather than blocking the UI.\n // NOTE: If the connection drops between the /server_info and\n // getSettings() probes, the app loads with an unvalidated key and\n // subsequent 401s won't trigger the auth screen (they come from\n // React Query hooks, not this bootstrap path). Acceptable for now\n // since the window is narrow and a page refresh recovers.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n console.warn(\n \"[agent-server] getSettings() probe failed (non-401):\",\n error,\n );\n }\n }\n\n cachedAgentServerInfo = serverInfo;\n return serverInfo;\n}\n"],"mappings":";;;;;;AAaA,IAAM,IAA+B,KAMjC,IAAgD,MAE9C,KAAsB,MACtB,MAAM,QAAQ,GAAY,aAAa,GAClC,EAAW,eAEb,MAGI,IAAb,cAAiD,MAAM;CACrD;CACA;CAEA,YACE,GACA,GACA;EACA,IAAM,IAAsB,GAAS,uBAAuB;AAQ5D,EAPA,MACE,IACI,6EACA,iHACL,EACD,KAAK,OAAO,+BACZ,KAAK,UAAU,KAAW,MAC1B,KAAK,sBAAsB;;GAIlB,KACX,MAEA,aAAiB,KAChB,OAAO,KAAU,cAChB,KACA,UAAU,KACV,EAAM,SAAS,+BAWN,KAA0B,MACrC,GAAgB,IAAI,EAAqB,GAAO,IAAI;AAEtD,SAAgB,IAA6B;AAC3C,KAAwB;;AAG1B,SAAgB,EAA2B,GAAkB;CAC3D,IAAM,IAAiB,EAAmB,EAAsB;AAIhE,QAHK,MAAM,QAAQ,EAAe,GAG3B,EAAe,SAAS,EAAS,GAF/B;;AAKX,SAAgB,EAAe,GAAgB;AAC7C,QACE,aAAiB,SACjB,EAAM,SAAS,eACf,YAAY,KACZ,OAAO,EAAM,UAAW;;AAQ5B,SAAgB,EAAqB,GAAgB,GAAyB;AAC5E,QACE,EAAe,EAAM,IAAK,EAA6B,WAAW;;AAItE,eAAsB,IAAsB;CAK1C,IAAM,IAAQ,GAA0B;AACxC,KAAI,CAAC,GAAO;AAMV,MALA,GAA4B,EAKxB,EAAY,GAAkB,CAAC,QAAQ,CACzC,OAAM,IAAI,EAA4B,yBAAyB,EAC7D,qBAAqB,IACtB,CAAC;AAIJ,SAAO;;CAGT,IAAM,IAAgB,EAA4B;EAChD,MAAM,EAAM;EACZ,eAAe,EAAM,UAAU;EAC/B,SAAS;EACV,CAAC,EACE;AAEJ,KAAI;AACF,MAAc,MAAM,IAAI,EACtB,EACD,CAAC,eAAe;UACV,GAAO;AAUd,QATA,GAA4B,EAIxB,EAAqB,GAAO,IAAI,GAC5B,IAIF,IAAI,EADM,aAAiB,QAAQ,EAAM,UAAU,KACX;;AAOhD,KAAI,GAAgB,CAClB,KAAI;AACF,QAAM,IAAI,EAAe,EAAc,CAAC,aAAa;UAC9C,GAAO;AAWd,MAAI,EAAqB,GAAO,IAAI,CAClC,OAAM;AAGR,UAAQ,KACN,wDACA,EACD;;AAKL,QADA,IAAwB,GACjB"}
1
+ {"version":3,"file":"agent-server-compatibility.js","names":[],"sources":["../../src/api/agent-server-compatibility.ts"],"sourcesContent":["import {\n ServerClient,\n SettingsClient,\n} from \"@openhands/typescript-client/clients\";\nimport type { ServerInfo as BaseServerInfo } from \"@openhands/typescript-client\";\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { isAuthRequired } from \"#/api/agent-server-config\";\nimport {\n getActiveBackend,\n getEffectiveLocalBackend,\n isNoBackend,\n} from \"#/api/backend-registry/active-store\";\nimport defaults from \"../../config/defaults.json\";\n\nconst AGENT_SERVER_INFO_TIMEOUT_MS = 5000;\nconst UNKNOWN_AGENT_SERVER_VERSION = \"unknown\";\n\nexport const MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION =\n defaults.compatibility.minimumAgentServer;\nexport const AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE =\n \"AGENT_SERVER_UNSUPPORTED_VERSION\";\n\nexport interface AgentServerInfo extends BaseServerInfo {\n usable_tools?: string[] | null;\n}\n\nlet cachedAgentServerInfo: AgentServerInfo | null = null;\n\nconst getAdvertisedTools = (serverInfo: AgentServerInfo | null) => {\n if (Array.isArray(serverInfo?.usable_tools)) {\n return serverInfo.usable_tools;\n }\n return null;\n};\n\nexport class AgentServerUnavailableError extends Error {\n readonly details: string | null;\n readonly noBackendConfigured: boolean;\n\n constructor(\n details?: string | null,\n options?: { noBackendConfigured?: boolean },\n ) {\n const noBackendConfigured = options?.noBackendConfigured ?? false;\n super(\n noBackendConfigured\n ? \"No agent server backend is configured yet. Add a backend to get started.\"\n : \"Could not connect to the configured agent server. Make sure it is running and reachable, then reload the page.\",\n );\n this.name = \"AgentServerUnavailableError\";\n this.details = details ?? null;\n this.noBackendConfigured = noBackendConfigured;\n }\n}\n\nexport const isAgentServerUnavailableError = (\n error: unknown,\n): error is AgentServerUnavailableError =>\n error instanceof AgentServerUnavailableError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"AgentServerUnavailableError\");\n\nexport class AgentServerUnsupportedVersionError extends AgentServerUnavailableError {\n readonly code = AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE;\n readonly actualVersion: string;\n readonly requiredVersion = MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION;\n\n constructor(actualVersion: string) {\n const message = `Agent Canvas requires agent-server ${MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION} or newer; this backend is running ${actualVersion}. Please upgrade the agent-server backend.`;\n super(message);\n this.name = \"AgentServerUnsupportedVersionError\";\n this.message = message;\n this.actualVersion = actualVersion;\n }\n}\n\nexport const isAgentServerUnsupportedVersionError = (\n error: unknown,\n): error is AgentServerUnsupportedVersionError =>\n error instanceof AgentServerUnsupportedVersionError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === AGENT_SERVER_UNSUPPORTED_VERSION_ERROR_CODE);\n\n/**\n * Returns true when the agent-server probe failed with HTTP 401.\n * In public mode this means the stored key is stale (server restarted\n * with a different `LOCAL_BACKEND_API_KEY`). Only meaningful when\n * auth is required — a 401 in local mode is a misconfiguration, not a\n * key-rotation event. Uses {@link isAuthRequired} so both the build-time\n * `VITE_AUTH_REQUIRED` flag and the runtime `window.__AGENT_CANVAS_AUTH_REQUIRED__`\n * injection (used by pre-built static binaries) are honoured.\n */\nexport const isAgentServerAuthError = (error: unknown): boolean =>\n isAuthRequired() && isSdkHttpStatusError(error, 401);\n\nexport function clearCachedAgentServerInfo() {\n cachedAgentServerInfo = null;\n}\n\nexport function isAgentServerToolAvailable(toolName: string) {\n const availableTools = getAdvertisedTools(cachedAgentServerInfo);\n if (!Array.isArray(availableTools)) {\n return true;\n }\n return availableTools.includes(toolName);\n}\n\nexport function isSdkHttpError(error: unknown) {\n return (\n error instanceof Error &&\n error.name === \"HttpError\" &&\n \"status\" in error &&\n typeof error.status === \"number\"\n );\n}\n\n/**\n * Narrows an SDK HTTP error to a specific status code.\n * Use instead of manually casting `(err as { status: number }).status`.\n */\nexport function isSdkHttpStatusError(error: unknown, status: number): boolean {\n return (\n isSdkHttpError(error) && (error as { status: number }).status === status\n );\n}\n\nfunction getReportedAgentServerVersion(serverInfo: AgentServerInfo) {\n return typeof serverInfo.version === \"string\" && serverInfo.version.trim()\n ? serverInfo.version.trim()\n : UNKNOWN_AGENT_SERVER_VERSION;\n}\n\nfunction compareAgentServerVersions(actual: string, required: string) {\n const parsedActual = parseAgentServerVersion(actual);\n const parsedRequired = parseAgentServerVersion(required);\n\n if (!parsedActual || !parsedRequired) {\n return null;\n }\n\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (parsedActual[key] > parsedRequired[key]) {\n return 1;\n }\n if (parsedActual[key] < parsedRequired[key]) {\n return -1;\n }\n }\n\n if (parsedActual.prerelease && !parsedRequired.prerelease) {\n return -1;\n }\n if (!parsedActual.prerelease && parsedRequired.prerelease) {\n return 1;\n }\n if (parsedActual.prerelease && parsedRequired.prerelease) {\n return parsedActual.prerelease.localeCompare(parsedRequired.prerelease);\n }\n\n return 0;\n}\n\nfunction parseAgentServerVersion(version: string) {\n const trimmed = version.trim().replace(/^v/, \"\");\n const [withoutBuild] = trimmed.split(\"+\");\n const [core, prerelease] = withoutBuild.split(\"-\", 2);\n const parts = core.split(\".\");\n\n if (parts.length !== 3) {\n return null;\n }\n\n const [major, minor, patch] = parts.map((part) => Number(part));\n if (\n ![major, minor, patch].every((part) => Number.isInteger(part) && part >= 0)\n ) {\n return null;\n }\n\n return { major, minor, patch, prerelease };\n}\n\nexport function assertAgentServerVersionIsSupported(\n serverInfo: AgentServerInfo,\n) {\n const actualVersion = getReportedAgentServerVersion(serverInfo);\n const comparison = compareAgentServerVersions(\n actualVersion,\n MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION,\n );\n\n if (comparison === null || comparison < 0) {\n clearCachedAgentServerInfo();\n throw new AgentServerUnsupportedVersionError(actualVersion);\n }\n}\n\nexport async function loadAgentServerInfo() {\n // The probe is a *local* agent-server concern — it verifies the runtime\n // hosting the GUI is reachable. It must NEVER run against the active\n // backend when that backend is cloud, because cloud hosts don't\n // expose /api/server_info and would fail with a CORS error besides.\n const local = getEffectiveLocalBackend();\n if (!local) {\n clearCachedAgentServerInfo();\n\n // Empty registry (NO_BACKEND sentinel) — the user has no backend\n // configured at all. Throw so root.tsx shows the manage-backends\n // modal instead of silently rendering a broken home page.\n if (isNoBackend(getActiveBackend().backend)) {\n throw new AgentServerUnavailableError(\"No backend configured\", {\n noBackendConfigured: true,\n });\n }\n\n // Active backend is cloud — no local probe needed.\n return null;\n }\n\n const clientOptions = getAgentServerClientOptions({\n host: local.host,\n sessionApiKey: local.apiKey || null,\n timeout: AGENT_SERVER_INFO_TIMEOUT_MS,\n });\n let serverInfo: AgentServerInfo;\n\n try {\n serverInfo = (await new ServerClient(\n clientOptions,\n ).getServerInfo()) as AgentServerInfo;\n } catch (error) {\n clearCachedAgentServerInfo();\n // Preserve 401 so root.tsx can show the auth screen (public mode).\n // All other HTTP errors (502, 503, etc.) mean the server is unreachable\n // or misconfigured — treat them as unavailable.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n const details = error instanceof Error ? error.message : null;\n throw new AgentServerUnavailableError(details);\n }\n\n assertAgentServerVersionIsSupported(serverInfo);\n\n // /server_info is unprotected, so a stale session key still gets 200.\n // In public mode, validate the key against a protected endpoint so a\n // server restart with a new LOCAL_BACKEND_API_KEY surfaces immediately\n // instead of letting the app load and fail on every subsequent call.\n if (isAuthRequired()) {\n try {\n await new SettingsClient(clientOptions).getSettings();\n } catch (error) {\n // Only rethrow 401 — that means the stored key is invalid /\n // rotated. Other HTTP errors (403, 5xx) and non-HTTP errors\n // (network, timeout) are swallowed: the server *is* up (we just\n // reached /server_info), so let the app proceed with an\n // unvalidated key rather than blocking the UI.\n // NOTE: If the connection drops between the /server_info and\n // getSettings() probes, the app loads with an unvalidated key and\n // subsequent 401s won't trigger the auth screen (they come from\n // React Query hooks, not this bootstrap path). Acceptable for now\n // since the window is narrow and a page refresh recovers.\n if (isSdkHttpStatusError(error, 401)) {\n throw error;\n }\n\n console.warn(\n \"[agent-server] getSettings() probe failed (non-401):\",\n error,\n );\n }\n }\n\n cachedAgentServerInfo = serverInfo;\n return serverInfo;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../agent-server-config.cjs`);var t=`default-local`,n=`Local`;function r(){let r=e.getAgentServerBaseUrl(),i=e.getAgentServerSessionApiKey();return!r||!i?null:{id:t,name:n,host:r,apiKey:i,kind:`local`}}exports.DEFAULT_LOCAL_BACKEND_ID=t,exports.DEFAULT_LOCAL_BACKEND_NAME=n,exports.makeDefaultLocalBackend=r;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../agent-server-config.cjs`);var t=`default-local`,n=`Local`;function r(){let r=e.getAgentServerBaseUrl(),i=e.getAgentServerSessionApiKey();return!r||!i?null:{id:t,name:n,host:r,apiKey:i,kind:`local`}}exports.SEEDED_DEFAULT_BACKEND_ID=t,exports.makeDefaultLocalBackend=r;
2
2
  //# sourceMappingURL=default-backend.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-backend.cjs","names":[],"sources":["../../../src/api/backend-registry/default-backend.ts"],"sourcesContent":["import {\n getAgentServerBaseUrl,\n getAgentServerSessionApiKey,\n} from \"../agent-server-config\";\nimport type { Backend } from \"./types\";\n\n/**\n * Stable id for the default local backend that is auto-seeded into the\n * registry when the launcher provides both a backend host and API key.\n * After seeding, this backend is a normal registered entry — the user can\n * rename it, edit its host/api key, or remove it like any other backend.\n */\nexport const DEFAULT_LOCAL_BACKEND_ID = \"default-local\";\n\nexport const DEFAULT_LOCAL_BACKEND_NAME = \"Local\";\n\n/**\n * Construct the default local backend from environment/runtime config.\n * Returns null unless both a backend location and API key are available.\n *\n * Used as the seed entry written to `openhands-backends` on first load;\n * if it returns null, onboarding is responsible for collecting backend\n * connection details from the user.\n */\nexport function makeDefaultLocalBackend(): Backend | null {\n const host = getAgentServerBaseUrl();\n const apiKey = getAgentServerSessionApiKey();\n\n if (!host || !apiKey) return null;\n\n return {\n id: DEFAULT_LOCAL_BACKEND_ID,\n name: DEFAULT_LOCAL_BACKEND_NAME,\n host,\n apiKey,\n kind: \"local\",\n };\n}\n"],"mappings":"8FAYA,IAAa,EAA2B,gBAE3B,EAA6B,QAU1C,SAAgB,GAA0C,CACxD,IAAM,EAAO,EAAA,uBAAuB,CAC9B,EAAS,EAAA,6BAA6B,CAI5C,MAFI,CAAC,GAAQ,CAAC,EAAe,KAEtB,CACL,GAAI,EACJ,KAAM,EACN,OACA,SACA,KAAM,QACP"}
1
+ {"version":3,"file":"default-backend.cjs","names":[],"sources":["../../../src/api/backend-registry/default-backend.ts"],"sourcesContent":["import {\n getAgentServerBaseUrl,\n getAgentServerSessionApiKey,\n} from \"../agent-server-config\";\nimport type { Backend } from \"./types\";\n\n/**\n * Stable id for the seeded default local backend that is auto-registered in\n * the backend registry when the launcher provides both a backend host and\n * API key. After seeding, this backend is a normal registered entry — the\n * user can rename it, edit its host/api key, or remove it like any other\n * backend.\n */\nexport const SEEDED_DEFAULT_BACKEND_ID = \"default-local\";\n\nexport const DEFAULT_LOCAL_BACKEND_NAME = \"Local\";\n\n/**\n * Construct the default local backend from environment/runtime config.\n * Returns null unless both a backend location and API key are available.\n *\n * Used as the seed entry written to `openhands-backends` on first load;\n * if it returns null, onboarding is responsible for collecting backend\n * connection details from the user.\n */\nexport function makeDefaultLocalBackend(): Backend | null {\n const host = getAgentServerBaseUrl();\n const apiKey = getAgentServerSessionApiKey();\n\n if (!host || !apiKey) return null;\n\n return {\n id: SEEDED_DEFAULT_BACKEND_ID,\n name: DEFAULT_LOCAL_BACKEND_NAME,\n host,\n apiKey,\n kind: \"local\",\n };\n}\n"],"mappings":"8FAaA,IAAa,EAA4B,gBAE5B,EAA6B,QAU1C,SAAgB,GAA0C,CACxD,IAAM,EAAO,EAAA,uBAAuB,CAC9B,EAAS,EAAA,6BAA6B,CAI5C,MAFI,CAAC,GAAQ,CAAC,EAAe,KAEtB,CACL,GAAI,EACJ,KAAM,EACN,OACA,SACA,KAAM,QACP"}
@@ -1,11 +1,12 @@
1
1
  import type { Backend } from "./types";
2
2
  /**
3
- * Stable id for the default local backend that is auto-seeded into the
4
- * registry when the launcher provides both a backend host and API key.
5
- * After seeding, this backend is a normal registered entry — the user can
6
- * rename it, edit its host/api key, or remove it like any other backend.
3
+ * Stable id for the seeded default local backend that is auto-registered in
4
+ * the backend registry when the launcher provides both a backend host and
5
+ * API key. After seeding, this backend is a normal registered entry — the
6
+ * user can rename it, edit its host/api key, or remove it like any other
7
+ * backend.
7
8
  */
8
- export declare const DEFAULT_LOCAL_BACKEND_ID = "default-local";
9
+ export declare const SEEDED_DEFAULT_BACKEND_ID = "default-local";
9
10
  export declare const DEFAULT_LOCAL_BACKEND_NAME = "Local";
10
11
  /**
11
12
  * Construct the default local backend from environment/runtime config.
@@ -12,6 +12,6 @@ function i() {
12
12
  };
13
13
  }
14
14
  //#endregion
15
- export { n as DEFAULT_LOCAL_BACKEND_ID, r as DEFAULT_LOCAL_BACKEND_NAME, i as makeDefaultLocalBackend };
15
+ export { n as SEEDED_DEFAULT_BACKEND_ID, i as makeDefaultLocalBackend };
16
16
 
17
17
  //# sourceMappingURL=default-backend.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"default-backend.js","names":[],"sources":["../../../src/api/backend-registry/default-backend.ts"],"sourcesContent":["import {\n getAgentServerBaseUrl,\n getAgentServerSessionApiKey,\n} from \"../agent-server-config\";\nimport type { Backend } from \"./types\";\n\n/**\n * Stable id for the default local backend that is auto-seeded into the\n * registry when the launcher provides both a backend host and API key.\n * After seeding, this backend is a normal registered entry — the user can\n * rename it, edit its host/api key, or remove it like any other backend.\n */\nexport const DEFAULT_LOCAL_BACKEND_ID = \"default-local\";\n\nexport const DEFAULT_LOCAL_BACKEND_NAME = \"Local\";\n\n/**\n * Construct the default local backend from environment/runtime config.\n * Returns null unless both a backend location and API key are available.\n *\n * Used as the seed entry written to `openhands-backends` on first load;\n * if it returns null, onboarding is responsible for collecting backend\n * connection details from the user.\n */\nexport function makeDefaultLocalBackend(): Backend | null {\n const host = getAgentServerBaseUrl();\n const apiKey = getAgentServerSessionApiKey();\n\n if (!host || !apiKey) return null;\n\n return {\n id: DEFAULT_LOCAL_BACKEND_ID,\n name: DEFAULT_LOCAL_BACKEND_NAME,\n host,\n apiKey,\n kind: \"local\",\n };\n}\n"],"mappings":";;AAYA,IAAa,IAA2B,iBAE3B,IAA6B;AAU1C,SAAgB,IAA0C;CACxD,IAAM,IAAO,GAAuB,EAC9B,IAAS,GAA6B;AAI5C,QAFI,CAAC,KAAQ,CAAC,IAAe,OAEtB;EACL,IAAI;EACJ,MAAM;EACN;EACA;EACA,MAAM;EACP"}
1
+ {"version":3,"file":"default-backend.js","names":[],"sources":["../../../src/api/backend-registry/default-backend.ts"],"sourcesContent":["import {\n getAgentServerBaseUrl,\n getAgentServerSessionApiKey,\n} from \"../agent-server-config\";\nimport type { Backend } from \"./types\";\n\n/**\n * Stable id for the seeded default local backend that is auto-registered in\n * the backend registry when the launcher provides both a backend host and\n * API key. After seeding, this backend is a normal registered entry — the\n * user can rename it, edit its host/api key, or remove it like any other\n * backend.\n */\nexport const SEEDED_DEFAULT_BACKEND_ID = \"default-local\";\n\nexport const DEFAULT_LOCAL_BACKEND_NAME = \"Local\";\n\n/**\n * Construct the default local backend from environment/runtime config.\n * Returns null unless both a backend location and API key are available.\n *\n * Used as the seed entry written to `openhands-backends` on first load;\n * if it returns null, onboarding is responsible for collecting backend\n * connection details from the user.\n */\nexport function makeDefaultLocalBackend(): Backend | null {\n const host = getAgentServerBaseUrl();\n const apiKey = getAgentServerSessionApiKey();\n\n if (!host || !apiKey) return null;\n\n return {\n id: SEEDED_DEFAULT_BACKEND_ID,\n name: DEFAULT_LOCAL_BACKEND_NAME,\n host,\n apiKey,\n kind: \"local\",\n };\n}\n"],"mappings":";;AAaA,IAAa,IAA4B,iBAE5B,IAA6B;AAU1C,SAAgB,IAA0C;CACxD,IAAM,IAAO,GAAuB,EAC9B,IAAS,GAA6B;AAI5C,QAFI,CAAC,KAAQ,CAAC,IAAe,OAEtB;EACL,IAAI;EACJ,MAAM;EACN;EACA;EACA,MAAM;EACP"}
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`./default-backend.cjs`);var t=`openhands-backends`,n=`openhands-active-backend`,r=`openhands-agent-server-config`;function i(e){return e===`local`||e===`cloud`}function a(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&t.id.length>0&&typeof t.name==`string`&&typeof t.host==`string`&&typeof t.apiKey==`string`&&i(t.kind)}function o(e){if(typeof e!=`string`)return null;let t=e.trim().replace(/\/+$/,``);return t?/^https?:\/\//i.test(t)?t:`http://${t}`:null}function s(){let t=window.localStorage.getItem(r);if(!t)return null;try{let n=JSON.parse(t),r=o(n.baseUrl),i=typeof n.sessionApiKey==`string`?n.sessionApiKey.trim():``;return!r||!i?null:{id:e.DEFAULT_LOCAL_BACKEND_ID,name:e.DEFAULT_LOCAL_BACKEND_NAME,host:r,apiKey:i,kind:`local`}}catch{return null}}function c(){window.localStorage.removeItem(r)}function l(e){return p(e),c(),e}function u(e){try{let{hostname:t}=new URL(e);return t===`localhost`||t===`127.0.0.1`||t===`::1`||t===`[::1]`}catch{return!1}}function d(e,t){return e.id!==`default-local`||e.kind!==`local`?!1:e.host===t.host||u(e.host)&&u(t.host)}function f(t){let n=e.makeDefaultLocalBackend();if(!n)return t;let r=!1,i=t.map(e=>!d(e,n)||e.apiKey===n.apiKey?e:(r=!0,{...e,apiKey:n.apiKey}));return r?(p(i),i):t}function p(e){if(!(typeof window>`u`))try{window.localStorage.setItem(t,JSON.stringify(e))}catch{}}function m(){if(typeof window>`u`)return[];try{let n=window.localStorage.getItem(t);if(n===null){let t=s();if(t)return l([t]);let n=e.makeDefaultLocalBackend();return n?l([n]):[]}let r=JSON.parse(n);if(!Array.isArray(r))return[];let i=r.filter(a);if(i.length===0){let t=e.makeDefaultLocalBackend();return t?l([t]):[]}let o=f(i);return c(),o}catch{return[]}}function h(e){if(!e)return null;try{let t=JSON.parse(e);if(typeof t!=`object`||!t||typeof t.backendId!=`string`)return null;let n=t.orgId;return{backendId:t.backendId,orgId:typeof n==`string`&&n.length>0?n:null}}catch{return null}}function g(e,t){try{return e?.getItem(t)??null}catch{return null}}function _(e,t,n){try{e?.setItem(t,n)}catch{}}function v(e,t){try{e?.removeItem(t)}catch{}}function y(){return typeof window>`u`?null:h(g(window.sessionStorage,n))||h(g(window.localStorage,n))}function b(e){if(typeof window>`u`)return;if(!e){v(window.sessionStorage,n),v(window.localStorage,n);return}let t=JSON.stringify({backendId:e.backendId,orgId:e.orgId??null});_(window.sessionStorage,n,t),_(window.localStorage,n,t)}exports.readStoredActiveBackend=y,exports.readStoredBackends=m,exports.writeStoredActiveBackend=b,exports.writeStoredBackends=p;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`./default-backend.cjs`);var t=`openhands-backends`,n=`openhands-active-backend`;function r(e){return e===`local`||e===`cloud`}function i(e){if(typeof e!=`object`||!e)return!1;let t=e;return typeof t.id==`string`&&t.id.length>0&&typeof t.name==`string`&&typeof t.host==`string`&&typeof t.apiKey==`string`&&r(t.kind)}function a(e){try{let{hostname:t}=new URL(e);return t===`localhost`||t===`127.0.0.1`||t===`::1`||t===`[::1]`}catch{return!1}}function o(e,t){return e.id!==`default-local`||e.kind!==`local`?!1:e.host===t.host||a(e.host)&&a(t.host)}function s(t){let n=e.makeDefaultLocalBackend();if(!n)return t;let r=!1,i=t.map(e=>!o(e,n)||e.apiKey===n.apiKey?e:(r=!0,{...e,apiKey:n.apiKey}));return r?(c(i),i):t}function c(e){if(!(typeof window>`u`))try{window.localStorage.setItem(t,JSON.stringify(e))}catch{}}function l(){if(typeof window>`u`)return[];try{let n=window.localStorage.getItem(t);if(n===null){let t=e.makeDefaultLocalBackend();return t?(c([t]),[t]):[]}let r=JSON.parse(n);if(!Array.isArray(r))return[];let a=r.filter(i);if(a.length===0){let t=e.makeDefaultLocalBackend();return t?(c([t]),[t]):[]}return s(a)}catch{return[]}}function u(e){if(!e)return null;try{let t=JSON.parse(e);if(typeof t!=`object`||!t||typeof t.backendId!=`string`)return null;let n=t.orgId;return{backendId:t.backendId,orgId:typeof n==`string`&&n.length>0?n:null}}catch{return null}}function d(e,t){try{return e?.getItem(t)??null}catch{return null}}function f(e,t,n){try{e?.setItem(t,n)}catch{}}function p(e,t){try{e?.removeItem(t)}catch{}}function m(){return typeof window>`u`?null:u(d(window.sessionStorage,n))||u(d(window.localStorage,n))}function h(e){if(typeof window>`u`)return;if(!e){p(window.sessionStorage,n),p(window.localStorage,n);return}let t=JSON.stringify({backendId:e.backendId,orgId:e.orgId??null});f(window.sessionStorage,n,t),f(window.localStorage,n,t)}exports.readStoredActiveBackend=m,exports.readStoredBackends=l,exports.writeStoredActiveBackend=h,exports.writeStoredBackends=c;
2
2
  //# sourceMappingURL=storage.cjs.map