@openhands/agent-canvas 1.8.0 → 1.9.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 (492) hide show
  1. package/README.md +1 -1
  2. package/README.windows.md +2 -2
  3. package/build/assets/{Trans-B7lYw4uD.js → Trans-Bwpzk1wT.js} +1 -1
  4. package/build/assets/{acp-providers-WUD4tfSq.js → acp-providers-C921BlYB.js} +1 -1
  5. package/build/assets/active-backend-context-BiwzkzDy.js +2 -0
  6. package/build/assets/agent-context-settings-DXNT_dcw.js +1 -0
  7. package/build/assets/agent-profiles-settings-BymJf3EP.js +1 -0
  8. package/build/assets/agent-server-conversation-service.api-CYSWw-2g.js +41 -0
  9. package/build/assets/agent-settings-BjgQQe-_.js +1 -0
  10. package/build/assets/{agent-settings-BGTyoT6X.js → agent-settings-WzqXk6B4.js} +2 -2
  11. package/build/assets/{alert-banner-eRyIwDyU.js → alert-banner-DR8EVyZM.js} +1 -1
  12. package/build/assets/api-error-message-e16L1kwH.js +1 -0
  13. package/build/assets/{api-key-entry-screen-JOx3SH1-.js → api-key-entry-screen-DI0I04O3.js} +1 -1
  14. package/build/assets/{app-settings-D53QZy5p.js → app-settings-DGistSFV.js} +1 -1
  15. package/build/assets/automation-C_eCrGyP.js +1 -0
  16. package/build/assets/automation-detail-DY6x2FW1.js +2 -0
  17. package/build/assets/automation-export-C09f-Lua.js +2 -0
  18. package/build/assets/automation-setup-route-CqKp0717.js +1 -0
  19. package/build/assets/automations-list-CqWJ7qXW.js +1 -0
  20. package/build/assets/{back-nav-button-C02hGa8t.js → back-nav-button-D4ngzpSh.js} +1 -1
  21. package/build/assets/backend-form-modal-B8D5hBzK.js +1 -0
  22. package/build/assets/{backend-synced-settings-badge-CQ9xtNWm.js → backend-synced-settings-badge-BnzI8Ysj.js} +1 -1
  23. package/build/assets/{badge-CzXbf7tR.js → badge-1Mf1iPcX.js} +1 -1
  24. package/build/assets/{base-modal-DkVyzFMt.js → base-modal-BBuy0WQQ.js} +1 -1
  25. package/build/assets/{brand-button-BUlDL-mz.js → brand-button-DGN6Y9o6.js} +1 -1
  26. package/build/assets/browser-D_ekTlTS.js +6 -0
  27. package/build/assets/{browser-tab-BijpUbdt.js → browser-tab-D4a4Ou_w.js} +1 -1
  28. package/build/assets/{chat-send-button-BKsVjhtA.js → chat-send-button-CgbcjD97.js} +1 -1
  29. package/build/assets/check-CPLXgluF.js +1 -0
  30. package/build/assets/chevron-down-CP4QHvyc.js +1 -0
  31. package/build/assets/circle-check-Dpy2_xSI.js +1 -0
  32. package/build/assets/{circle-plus-check-toggle-DdjUiOo1.js → circle-plus-check-toggle-yTAS-nX3.js} +1 -1
  33. package/build/assets/cloud-funnel-analytics-CEOl5Gxr.js +1 -0
  34. package/build/assets/{combobox-caret-Dl9UtvD6.js → combobox-caret-Bd2yySnF.js} +1 -1
  35. package/build/assets/command-menu-Bj6X4ckE.js +1 -0
  36. package/build/assets/condenser-settings-EAXQNR2E.js +1 -0
  37. package/build/assets/{confirmation-modal-CRBJSllP.js → confirmation-modal-NCUPr2-O.js} +1 -1
  38. package/build/assets/{context-menu-list-item-FGaafXGh.js → context-menu-list-item-CrCrYuPF.js} +1 -1
  39. package/build/assets/conversation-BzyIcSwr.js +1 -0
  40. package/build/assets/conversation-CUJ0Vo8g.js +90 -0
  41. package/build/assets/conversation-panel-BzyIcSwr.js +1 -0
  42. package/build/assets/conversation-state-store-F62HvuI1.js +1 -0
  43. package/build/assets/{conversation-tab-empty-state-CDjvNgpG.js → conversation-tab-empty-state-BCZ7rUMH.js} +1 -1
  44. package/build/assets/{copy-Drwu97Gx.js → copy-DCmZtz6n.js} +1 -1
  45. package/build/assets/{copy-to-clipboard-button-NbN1clVr.js → copy-to-clipboard-button-D_Lp6-Fl.js} +1 -1
  46. package/build/assets/{device-verify-CDm_WrVu.js → device-verify-DLmolX8Q.js} +1 -1
  47. package/build/assets/{dropdown-classes-CqA2BTCL.js → dropdown-classes-BB8rzqXL.js} +1 -1
  48. package/build/assets/{entry.client-BO2KQj0y.js → entry.client-BbIYOsIg.js} +2 -2
  49. package/build/assets/{enum-filter-dropdown-DSqPZnsD.js → enum-filter-dropdown-C08-srev.js} +1 -1
  50. package/build/assets/{environment-switch-overlay-mGl2pqqx.js → environment-switch-overlay-BepBBX66.js} +1 -1
  51. package/build/assets/{extensions-hub-Br3Lgynp.js → extensions-hub-R3KNv-5V.js} +1 -1
  52. package/build/assets/{extensions-navigation-BQmstKDZ.js → extensions-navigation-CfWFmI1I.js} +1 -1
  53. package/build/assets/{external-link-D9B2QMPf.js → external-link-BdBSg8rk.js} +1 -1
  54. package/build/assets/files-tab-DEq8MbHu.js +1 -0
  55. package/build/assets/{form-control-classes-CtVAktAy.js → form-control-classes-DAfsCJTe.js} +1 -1
  56. package/build/assets/{format-time-delta-DICE64sz.js → format-time-delta-CxfPJpzC.js} +1 -1
  57. package/build/assets/git-provider-icon-BZqqUPlm.js +1 -0
  58. package/build/assets/git-repo-dropdown-9WKINV6J.js +1 -0
  59. package/build/assets/git-repo-dropdown-DEpOwUez.js +1 -0
  60. package/build/assets/{highlighted-source-view-KMsA9c4a.js → highlighted-source-view-CX9oIoVT.js} +1 -1
  61. package/build/assets/home-CY0JaxiY.js +1 -0
  62. package/build/assets/home-CaNWlVvB.js +1 -0
  63. package/build/assets/home-store-Ch1ErdBc.js +1 -0
  64. package/build/assets/index-home-CaNWlVvB.js +1 -0
  65. package/build/assets/info-CmWQXtRQ.js +1 -0
  66. package/build/assets/install-server-modal-BWrudmZU.js +1 -0
  67. package/build/assets/{launch-DjkKw55l.js → launch-B1POpHuP.js} +1 -1
  68. package/build/assets/{list-todo-BpAf7aOT.js → list-todo-DtiL3lTp.js} +1 -1
  69. package/build/assets/llm-not-configured-banner-3tMsM4K6.js +27 -0
  70. package/build/assets/{llm-settings-D8zNkIlP.js → llm-settings-CXo8iPNW.js} +1 -1
  71. package/build/assets/llm-settings-D0W8mJDk.js +1 -0
  72. package/build/assets/{llm-subscription-service-COTgZc1C.js → llm-subscription-service-DBJbfd8Z.js} +1 -1
  73. package/build/assets/loader-circle-B4QDBARx.js +1 -0
  74. package/build/assets/{loading-spinner-DRFyh6Iy.js → loading-spinner-DfZ_bhV7.js} +1 -1
  75. package/build/assets/{manage-backends-modal-DiRWE3tJ.js → manage-backends-modal-CwyWsiag.js} +1 -1
  76. package/build/assets/manifest-39f4789d.js +1 -0
  77. package/build/assets/markdown-renderer-DgiLLhW6.js +8 -0
  78. package/build/assets/mcp-DXG9LWrI.js +9 -0
  79. package/build/assets/mcp-marketplace-utils-DFmhKc5s.js +1 -0
  80. package/build/assets/messages-kBjKaAeA.js +40 -0
  81. package/build/assets/{modal-body-C3bGicn4.js → modal-body-CMsDpalT.js} +1 -1
  82. package/build/assets/{modal-classes-DFFO6BMU.js → modal-classes-B6PDrxXo.js} +1 -1
  83. package/build/assets/{modal-close-button-vxkAIRyZ.js → modal-close-button-DyxBZaAb.js} +1 -1
  84. package/build/assets/{onboarding-DWuFieEA.js → onboarding-47hh2IHA.js} +1 -1
  85. package/build/assets/{onboarding-modal-C8m72Dpb.js → onboarding-modal-9BuvvROo.js} +1 -1
  86. package/build/assets/{organization-service.api-CQ73CB-S.js → organization-service.api-UDy63-oC.js} +1 -1
  87. package/build/assets/{pencil-DzW2GB2M.js → pencil-BjgtZmWp.js} +1 -1
  88. package/build/assets/{planner-tab-YG0bGxDY.js → planner-tab-BWk8885v.js} +1 -1
  89. package/build/assets/{plugins-management-service-ijhH8OSh.js → plugins-management-service-CjkgF2dd.js} +1 -1
  90. package/build/assets/plus-DrKuuvMe.js +1 -0
  91. package/build/assets/{profiles-service.api-C32pPm70.js → profiles-service.api-CukSFLzz.js} +1 -1
  92. package/build/assets/{providers-DuSn9s2i.js → providers-CqUWC85T.js} +1 -1
  93. package/build/assets/{proxy-BiyDhMBd.js → proxy-BBUG3sd2.js} +1 -1
  94. package/build/assets/{puzzle-DlqT0yvr.js → puzzle-BoNc6zZ8.js} +1 -1
  95. package/build/assets/recommended-automations-launcher-ejxy1P27.js +1 -0
  96. package/build/assets/{refresh-cw-Br5254f4.js → refresh-cw-BrM5ZAZD.js} +1 -1
  97. package/build/assets/root-5S-M8SYa.js +2 -0
  98. package/build/assets/root-DZ39lS5f.css +1 -0
  99. package/build/assets/root-layout-BPqoa0gv.js +3 -0
  100. package/build/assets/{schema-field-htfNouTG.js → schema-field-nImDoY6-.js} +1 -1
  101. package/build/assets/{sdk-section-page-D0K1dBQY.js → sdk-section-page-BxMrtUNV.js} +1 -1
  102. package/build/assets/search-Dc2qR4O2.js +1 -0
  103. package/build/assets/{secrets-service-Dbv5Zb8G.js → secrets-service-Dhjh3HhH.js} +1 -1
  104. package/build/assets/{secrets-settings-Da4SSaX9.js → secrets-settings-CPdxceT_.js} +1 -1
  105. package/build/assets/segmented-toggle-Do6oyepX.js +1 -0
  106. package/build/assets/{settings-F4a09IxY.js → settings-BRbnfKEm.js} +1 -1
  107. package/build/assets/{settings-dropdown-input-jOiv5Yrk.js → settings-dropdown-input-DYCULKpp.js} +1 -1
  108. package/build/assets/{settings-index-CyJBf5NA.js → settings-index-C9o2NBO0.js} +1 -1
  109. package/build/assets/settings-input-B-q2gkVy.js +1 -0
  110. package/build/assets/{settings-list-classes-VqMzkYYt.js → settings-list-classes-WpQi0q1L.js} +1 -1
  111. package/build/assets/{settings-modal-C-S1NpbC.js → settings-modal-CEK0AIx6.js} +1 -1
  112. package/build/assets/{settings-service.api-CTJRrvMu.js → settings-service.api-CZiPD8__.js} +1 -1
  113. package/build/assets/{settings-switch-B405oU_v.js → settings-switch-LqKdGxHL.js} +1 -1
  114. package/build/assets/shared-conversation-Bu-dQlgp.js +1 -0
  115. package/build/assets/{sidebar-layout-BGMuyC86.js → sidebar-layout-oHBGQmLh.js} +1 -1
  116. package/build/assets/{sidebar-mobile-menu-toggle-xiKoUfGa.js → sidebar-mobile-menu-toggle-ND-hgygu.js} +1 -1
  117. package/build/assets/{sidebar-nav-link-DA4_ct9G.js → sidebar-nav-link-CrujNA09.js} +1 -1
  118. package/build/assets/{sidebar-store-FRJ3rADB.js → sidebar-store-Bui-WNEr.js} +1 -1
  119. package/build/assets/{skill-card-pill-row-BMdhr_sd.js → skill-card-pill-row-CZBI7OqH.js} +1 -1
  120. package/build/assets/{skill-icon-badge-CGUkgcVH.js → skill-icon-badge-BOov_phZ.js} +1 -1
  121. package/build/assets/{skills-plugins-C5eJnyft.js → skills-plugins-D0PiHWAD.js} +1 -1
  122. package/build/assets/{skills-settings-pUxMr6WZ.js → skills-settings-B43KArIz.js} +2 -2
  123. package/build/assets/{styled-tooltip-B3kIdVyH.js → styled-tooltip-C7grwnOX.js} +1 -1
  124. package/build/assets/{task-list-tab-B3k4W1cK.js → task-list-tab-R3ac6m7O.js} +1 -1
  125. package/build/assets/{terminal-CBI_41Zc.js → terminal-yqkNdEAx.js} +1 -1
  126. package/build/assets/{toggle-switch-DYRr9CAR.js → toggle-switch-BeSrbgCg.js} +1 -1
  127. package/build/assets/{trash-2-gZPlx23R.js → trash-2-wW5TWcdN.js} +1 -1
  128. package/build/assets/{typography-B1UxuuEC.js → typography-iYhzLlHO.js} +1 -1
  129. package/build/assets/{use-acp-credential-form-CjSvKWFH.js → use-acp-credential-form-DUxbxmbq.js} +1 -1
  130. package/build/assets/{use-activate-agent-profile-DCRf47e-.js → use-activate-agent-profile-CDHA52tC.js} +1 -1
  131. package/build/assets/use-agent-profiles-TsOdIyw5.js +1 -0
  132. package/build/assets/{use-can-manage-org-profiles-vBiP7rHF.js → use-can-manage-org-profiles-Bt1M71u5.js} +1 -1
  133. package/build/assets/{use-cloud-current-user-id-BMq9gw93.js → use-cloud-current-user-id-DWt7HCgf.js} +1 -1
  134. package/build/assets/use-config-CxlEdf_v.js +1 -0
  135. package/build/assets/{use-create-conversation-CakhLF0X.js → use-create-conversation-nOJ6Um5h.js} +1 -1
  136. package/build/assets/{use-create-secret-RT4QtSS9.js → use-create-secret-Dj5ang9x.js} +1 -1
  137. package/build/assets/use-is-authed-BT7Iud4U.js +1 -0
  138. package/build/assets/{use-is-creating-conversation-CIAcnd8M.js → use-is-creating-conversation-CAggrM75.js} +1 -1
  139. package/build/assets/use-llm-profiles-2Wc2db8u.js +1 -0
  140. package/build/assets/{use-onboarding-completion-CJU4MNAY.js → use-onboarding-completion-gxQlcEy2.js} +1 -1
  141. package/build/assets/{use-plugins-marketplace-D-93nqtJ.js → use-plugins-marketplace-CVO7sXYR.js} +1 -1
  142. package/build/assets/use-save-agent-profile-D0wC5ExW.js +1 -0
  143. package/build/assets/{use-save-settings--C6LZXfI.js → use-save-settings-L3aMaDeS.js} +1 -1
  144. package/build/assets/{use-settings-DIAo5KFk.js → use-settings-8nt3DGxW.js} +1 -1
  145. package/build/assets/use-settings-nav-items-DHAAD-zk.js +16 -0
  146. package/build/assets/{use-skills-D_mLhYNa.js → use-skills-CE6miQ3r.js} +1 -1
  147. package/build/assets/use-tracking-BGboadaZ.js +68 -0
  148. package/build/assets/{use-user-conversation-DhcAEyJX.js → use-user-conversation-BIIpGUgM.js} +1 -1
  149. package/build/assets/useInfiniteQuery-BLRVmVPU.js +1 -0
  150. package/build/assets/{useMutation-DHLpZ6J0.js → useMutation-CaSHLnX0.js} +1 -1
  151. package/build/assets/{useQueries-B3T1a7qt.js → useQueries--d_WWAzc.js} +1 -1
  152. package/build/assets/{useQuery-B38jBavx.js → useQuery-DiPh8LRJ.js} +1 -1
  153. package/build/assets/utils-BgGG1znF.js +1 -0
  154. package/build/assets/{vendor~browser-CIoZCqGs.js → vendor~browser-IVYgIgG1.js} +1 -1
  155. package/build/assets/{vendor~entry.client-Di4qO77Y.js → vendor~entry.client-BcYIVQvB.js} +1 -1
  156. package/build/assets/{vendor~entry.client-BfviqoVc.js → vendor~entry.client-CXM9oiAk.js} +1 -1
  157. package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~g4xrpilz-CYPMCkX1.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~b0bpqexo-CbTboogo.js} +1 -1
  158. package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~f9xdmd0z-DLMP7bZx.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~d4by102p-C2f0ZhS-.js} +1 -1
  159. package/build/assets/{vendor~files-tab-atebg0iG.js → vendor~files-tab-C7RmQJwN.js} +1 -1
  160. package/build/assets/{vendor~index-home~home~conversation-panel~conversation-G9DMrR7m.js → vendor~index-home~home~conversation-panel~conversation-Bqp1ZqJM.js} +1 -1
  161. package/build/assets/{vendor~root-layout~conversation-panel~conversation-DEhW1h3I.js → vendor~root-layout~conversation-panel~conversation-BCn8lzeG.js} +1 -1
  162. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation~automation-setup-route-B_L-gcOG.js +1 -0
  163. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-sjx0x5ac.js +1 -0
  164. package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~automation-setup-route~onboarding-modal-D7IDevqN.js +1 -0
  165. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~bi2r7bko-VFnwct3q.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~dfc8ddxy-tTyxnjXT.js} +1 -1
  166. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~hakxo2tj-ClV0p9g3.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~gy8zbn65-CGt6bWRT.js} +1 -1
  167. package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~eywn6ulz-BKxxr74w.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~skills-setti~dufan6ng-Dtdw8H0q.js} +17 -4
  168. package/build/assets/{verification-settings-Vr5cN4md.js → verification-settings-DBsnSXC3.js} +1 -1
  169. package/build/assets/x-omAzpXkl.js +1 -0
  170. package/build/index.html +4 -4
  171. package/build/locales/ar/openhands.json +37 -2
  172. package/build/locales/ca/openhands.json +37 -2
  173. package/build/locales/de/openhands.json +37 -2
  174. package/build/locales/en/openhands.json +38 -3
  175. package/build/locales/es/openhands.json +37 -2
  176. package/build/locales/fr/openhands.json +37 -2
  177. package/build/locales/it/openhands.json +37 -2
  178. package/build/locales/ja/openhands.json +37 -2
  179. package/build/locales/ko-KR/openhands.json +37 -2
  180. package/build/locales/no/openhands.json +37 -2
  181. package/build/locales/pt/openhands.json +37 -2
  182. package/build/locales/tr/openhands.json +37 -2
  183. package/build/locales/uk/openhands.json +37 -2
  184. package/build/locales/zh-CN/openhands.json +37 -2
  185. package/build/locales/zh-TW/openhands.json +37 -2
  186. package/config/defaults.json +1 -1
  187. package/dist/api/agent-server-adapter.cjs +3 -3
  188. package/dist/api/agent-server-adapter.cjs.map +1 -1
  189. package/dist/api/agent-server-adapter.d.ts +46 -6
  190. package/dist/api/agent-server-adapter.js +187 -168
  191. package/dist/api/agent-server-adapter.js.map +1 -1
  192. package/dist/api/agent-server-compatibility.cjs +1 -1
  193. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  194. package/dist/api/agent-server-compatibility.d.ts +4 -0
  195. package/dist/api/agent-server-compatibility.js +41 -38
  196. package/dist/api/agent-server-compatibility.js.map +1 -1
  197. package/dist/api/automation-service/automation-service.api.cjs +1 -1
  198. package/dist/api/automation-service/automation-service.api.cjs.map +1 -1
  199. package/dist/api/automation-service/automation-service.api.d.ts +20 -0
  200. package/dist/api/automation-service/automation-service.api.js +99 -62
  201. package/dist/api/automation-service/automation-service.api.js.map +1 -1
  202. package/dist/components/conversation-events/chat/event-content-helpers/get-action-event-title.cjs +2 -0
  203. package/dist/components/conversation-events/chat/event-content-helpers/get-action-event-title.cjs.map +1 -0
  204. package/dist/components/conversation-events/chat/event-content-helpers/get-action-event-title.d.ts +12 -0
  205. package/dist/components/conversation-events/chat/event-content-helpers/get-action-event-title.js +94 -0
  206. package/dist/components/conversation-events/chat/event-content-helpers/get-action-event-title.js.map +1 -0
  207. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs +1 -1
  208. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs.map +1 -1
  209. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js +31 -90
  210. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js.map +1 -1
  211. package/dist/components/features/automations/recommended-automations-launcher.d.ts +0 -7
  212. package/dist/components/features/automations/recommended-automations-section.d.ts +0 -6
  213. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  214. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  215. package/dist/components/features/backends/backend-form-modal.js +568 -358
  216. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  217. package/dist/components/features/backends/device-flow-auth.cjs +1 -1
  218. package/dist/components/features/backends/device-flow-auth.cjs.map +1 -1
  219. package/dist/components/features/backends/device-flow-auth.d.ts +9 -1
  220. package/dist/components/features/backends/device-flow-auth.js +56 -55
  221. package/dist/components/features/backends/device-flow-auth.js.map +1 -1
  222. package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
  223. package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
  224. package/dist/components/features/backends/manage-backends-modal.js +1 -1
  225. package/dist/components/features/backends/manage-backends-modal.js.map +1 -1
  226. package/dist/components/features/chat/chat-interface.cjs +1 -1
  227. package/dist/components/features/chat/chat-interface.cjs.map +1 -1
  228. package/dist/components/features/chat/chat-interface.js +105 -105
  229. package/dist/components/features/chat/chat-interface.js.map +1 -1
  230. package/dist/components/features/chat/chat-message.cjs +1 -1
  231. package/dist/components/features/chat/chat-message.cjs.map +1 -1
  232. package/dist/components/features/chat/chat-message.d.ts +2 -1
  233. package/dist/components/features/chat/chat-message.js +59 -49
  234. package/dist/components/features/chat/chat-message.js.map +1 -1
  235. package/dist/components/features/chat/pending-user-messages.cjs +1 -1
  236. package/dist/components/features/chat/pending-user-messages.cjs.map +1 -1
  237. package/dist/components/features/chat/pending-user-messages.js +4 -1
  238. package/dist/components/features/chat/pending-user-messages.js.map +1 -1
  239. package/dist/components/features/chat/typing-indicator.cjs +1 -1
  240. package/dist/components/features/chat/typing-indicator.cjs.map +1 -1
  241. package/dist/components/features/chat/typing-indicator.d.ts +8 -1
  242. package/dist/components/features/chat/typing-indicator.js +94 -10
  243. package/dist/components/features/chat/typing-indicator.js.map +1 -1
  244. package/dist/components/features/command-menu/command-menu-items.d.ts +5 -1
  245. package/dist/components/features/files-tab/segmented-toggle.cjs +1 -1
  246. package/dist/components/features/files-tab/segmented-toggle.cjs.map +1 -1
  247. package/dist/components/features/files-tab/segmented-toggle.d.ts +2 -0
  248. package/dist/components/features/files-tab/segmented-toggle.js +17 -14
  249. package/dist/components/features/files-tab/segmented-toggle.js.map +1 -1
  250. package/dist/components/features/manifest/manifest-form-field.d.ts +27 -0
  251. package/dist/components/features/manifest/manifest-prerequisites-step.d.ts +11 -0
  252. package/dist/components/features/manifest/manifest-review-step.d.ts +14 -0
  253. package/dist/components/features/manifest/manifest-setup-dialog.d.ts +14 -0
  254. package/dist/components/features/settings/settings-input.cjs +1 -1
  255. package/dist/components/features/settings/settings-input.cjs.map +1 -1
  256. package/dist/components/features/settings/settings-input.d.ts +6 -0
  257. package/dist/components/features/settings/settings-input.js +13 -8
  258. package/dist/components/features/settings/settings-input.js.map +1 -1
  259. package/dist/components/features/sidebar/sidebar-rail-body.cjs +1 -1
  260. package/dist/components/features/sidebar/sidebar-rail-body.cjs.map +1 -1
  261. package/dist/components/features/sidebar/sidebar-rail-body.js +124 -123
  262. package/dist/components/features/sidebar/sidebar-rail-body.js.map +1 -1
  263. package/dist/config/defaults.cjs +1 -1
  264. package/dist/config/defaults.cjs.map +1 -1
  265. package/dist/config/defaults.js +1 -1
  266. package/dist/config/defaults.js.map +1 -1
  267. package/dist/hooks/query/query-keys.cjs.map +1 -1
  268. package/dist/hooks/query/query-keys.d.ts +4 -0
  269. package/dist/hooks/query/query-keys.js.map +1 -1
  270. package/dist/hooks/query/use-manifest-capabilities.d.ts +21 -0
  271. package/dist/hooks/query/use-manifest-prerequisites.d.ts +24 -0
  272. package/dist/hooks/use-llm-configured.cjs +1 -1
  273. package/dist/hooks/use-llm-configured.cjs.map +1 -1
  274. package/dist/hooks/use-llm-configured.js +2 -1
  275. package/dist/hooks/use-llm-configured.js.map +1 -1
  276. package/dist/hooks/use-manifest-preflight.d.ts +18 -0
  277. package/dist/hooks/use-tracking.cjs +1 -1
  278. package/dist/hooks/use-tracking.cjs.map +1 -1
  279. package/dist/hooks/use-tracking.d.ts +14 -0
  280. package/dist/hooks/use-tracking.js +19 -1
  281. package/dist/hooks/use-tracking.js.map +1 -1
  282. package/dist/i18n/declaration.cjs +1 -1
  283. package/dist/i18n/declaration.cjs.map +1 -1
  284. package/dist/i18n/declaration.d.ts +36 -1
  285. package/dist/i18n/declaration.js +1 -1
  286. package/dist/i18n/declaration.js.map +1 -1
  287. package/dist/i18n/translation.cjs +2 -2
  288. package/dist/i18n/translation.cjs.map +1 -1
  289. package/dist/i18n/translation.js +611 -16
  290. package/dist/i18n/translation.js.map +1 -1
  291. package/dist/icons/external-link.cjs +2 -0
  292. package/dist/icons/external-link.cjs.map +1 -0
  293. package/dist/icons/external-link.js +22 -0
  294. package/dist/icons/external-link.js.map +1 -0
  295. package/dist/icons/server.cjs +2 -0
  296. package/dist/icons/server.cjs.map +1 -0
  297. package/dist/icons/server.js +17 -0
  298. package/dist/icons/server.js.map +1 -0
  299. package/dist/locales/ar/openhands.json +37 -2
  300. package/dist/locales/ca/openhands.json +37 -2
  301. package/dist/locales/de/openhands.json +37 -2
  302. package/dist/locales/en/openhands.json +38 -3
  303. package/dist/locales/es/openhands.json +37 -2
  304. package/dist/locales/fr/openhands.json +37 -2
  305. package/dist/locales/it/openhands.json +37 -2
  306. package/dist/locales/ja/openhands.json +37 -2
  307. package/dist/locales/ko-KR/openhands.json +37 -2
  308. package/dist/locales/no/openhands.json +37 -2
  309. package/dist/locales/pt/openhands.json +37 -2
  310. package/dist/locales/tr/openhands.json +37 -2
  311. package/dist/locales/uk/openhands.json +37 -2
  312. package/dist/locales/zh-CN/openhands.json +37 -2
  313. package/dist/locales/zh-TW/openhands.json +37 -2
  314. package/dist/manifests/automation-interface.cjs +2 -0
  315. package/dist/manifests/automation-interface.cjs.map +1 -0
  316. package/dist/manifests/automation-interface.d.ts +44 -0
  317. package/dist/manifests/automation-interface.js +81 -0
  318. package/dist/manifests/automation-interface.js.map +1 -0
  319. package/dist/manifests/automation-setup.cjs +2 -0
  320. package/dist/manifests/automation-setup.cjs.map +1 -0
  321. package/dist/manifests/automation-setup.d.ts +52 -0
  322. package/dist/manifests/automation-setup.js +8 -0
  323. package/dist/manifests/automation-setup.js.map +1 -0
  324. package/dist/manifests/interface-validation.cjs +2 -0
  325. package/dist/manifests/interface-validation.cjs.map +1 -0
  326. package/dist/manifests/interface-validation.d.ts +27 -0
  327. package/dist/manifests/interface-validation.js +182 -0
  328. package/dist/manifests/interface-validation.js.map +1 -0
  329. package/dist/manifests/manifest-actions.d.ts +15 -0
  330. package/dist/manifests/manifest-capabilities.d.ts +25 -0
  331. package/dist/manifests/manifest-error-map.d.ts +40 -0
  332. package/dist/manifests/manifest-local-validation.d.ts +56 -0
  333. package/dist/manifests/manifest-registry.cjs +2 -0
  334. package/dist/manifests/manifest-registry.cjs.map +1 -0
  335. package/dist/manifests/manifest-registry.d.ts +15 -0
  336. package/dist/manifests/manifest-registry.js +26 -0
  337. package/dist/manifests/manifest-registry.js.map +1 -0
  338. package/dist/manifests/manifest-sources.cjs +2 -0
  339. package/dist/manifests/manifest-sources.cjs.map +1 -0
  340. package/dist/manifests/manifest-sources.d.ts +15 -0
  341. package/dist/manifests/manifest-sources.js +8 -0
  342. package/dist/manifests/manifest-sources.js.map +1 -0
  343. package/dist/manifests/manifest-template.d.ts +18 -0
  344. package/dist/manifests/manifest-validation.cjs +2 -0
  345. package/dist/manifests/manifest-validation.cjs.map +1 -0
  346. package/dist/manifests/manifest-validation.d.ts +30 -0
  347. package/dist/manifests/manifest-validation.js +145 -0
  348. package/dist/manifests/manifest-validation.js.map +1 -0
  349. package/dist/manifests/types.cjs +2 -0
  350. package/dist/manifests/types.cjs.map +1 -0
  351. package/dist/manifests/types.d.ts +227 -0
  352. package/dist/manifests/types.js +6 -0
  353. package/dist/manifests/types.js.map +1 -0
  354. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.cjs +9 -0
  355. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.cjs.map +1 -0
  356. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.js +75 -0
  357. package/dist/node_modules/@openhands/extensions/automations/catalog/github-pr-reviewer/manifest.js.map +1 -0
  358. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.cjs +9 -0
  359. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.cjs.map +1 -0
  360. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.js +78 -0
  361. package/dist/node_modules/@openhands/extensions/automations/catalog/github-repo-monitor/manifest.js.map +1 -0
  362. package/dist/node_modules/@openhands/extensions/automations/catalog/incident-retrospective-drafter/manifest.cjs +17 -0
  363. package/dist/node_modules/@openhands/extensions/automations/catalog/incident-retrospective-drafter/manifest.cjs.map +1 -0
  364. package/dist/node_modules/@openhands/extensions/automations/catalog/incident-retrospective-drafter/manifest.js +89 -0
  365. package/dist/node_modules/@openhands/extensions/automations/catalog/incident-retrospective-drafter/manifest.js.map +1 -0
  366. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-pr/manifest.cjs +10 -0
  367. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-pr/manifest.cjs.map +1 -0
  368. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-pr/manifest.js +17 -0
  369. package/dist/node_modules/@openhands/extensions/automations/catalog/jira-issue-to-pr/manifest.js.map +1 -0
  370. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-triage-assistant/manifest.cjs +9 -0
  371. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-triage-assistant/manifest.cjs.map +1 -0
  372. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-triage-assistant/manifest.js +15 -0
  373. package/dist/node_modules/@openhands/extensions/automations/catalog/linear-triage-assistant/manifest.js.map +1 -0
  374. package/dist/node_modules/@openhands/extensions/automations/catalog/research-brief-writer/manifest.cjs +9 -0
  375. package/dist/node_modules/@openhands/extensions/automations/catalog/research-brief-writer/manifest.cjs.map +1 -0
  376. package/dist/node_modules/@openhands/extensions/automations/catalog/research-brief-writer/manifest.js +18 -0
  377. package/dist/node_modules/@openhands/extensions/automations/catalog/research-brief-writer/manifest.js.map +1 -0
  378. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-channel-monitor/manifest.cjs +9 -0
  379. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-channel-monitor/manifest.cjs.map +1 -0
  380. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-channel-monitor/manifest.js +14 -0
  381. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-channel-monitor/manifest.js.map +1 -0
  382. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-standup-digest/manifest.cjs +9 -0
  383. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-standup-digest/manifest.cjs.map +1 -0
  384. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-standup-digest/manifest.js +14 -0
  385. package/dist/node_modules/@openhands/extensions/automations/catalog/slack-standup-digest/manifest.js.map +1 -0
  386. package/dist/node_modules/@openhands/extensions/automations/catalog-index.cjs +2 -0
  387. package/dist/node_modules/@openhands/extensions/automations/catalog-index.cjs.map +1 -0
  388. package/dist/node_modules/@openhands/extensions/automations/catalog-index.js +23 -0
  389. package/dist/node_modules/@openhands/extensions/automations/catalog-index.js.map +1 -0
  390. package/dist/node_modules/@openhands/extensions/automations/index.cjs +2 -0
  391. package/dist/node_modules/@openhands/extensions/automations/index.cjs.map +1 -0
  392. package/dist/node_modules/@openhands/extensions/automations/index.js +18 -0
  393. package/dist/node_modules/@openhands/extensions/automations/index.js.map +1 -0
  394. package/dist/node_modules/@openhands/extensions/automations/interface.cjs +2 -0
  395. package/dist/node_modules/@openhands/extensions/automations/interface.cjs.map +1 -0
  396. package/dist/node_modules/@openhands/extensions/automations/interface.js +89 -0
  397. package/dist/node_modules/@openhands/extensions/automations/interface.js.map +1 -0
  398. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.cjs +1 -1
  399. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.cjs.map +1 -1
  400. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.js +3 -3
  401. package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.js.map +1 -1
  402. package/dist/node_modules/@openhands/extensions/skills/index.cjs +17 -4
  403. package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
  404. package/dist/node_modules/@openhands/extensions/skills/index.js +5 -5
  405. package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
  406. package/dist/node_modules/lucide-react/dist/esm/icons/monitor.cjs +2 -0
  407. package/dist/node_modules/lucide-react/dist/esm/icons/monitor.cjs.map +1 -0
  408. package/dist/node_modules/lucide-react/dist/esm/icons/monitor.js +29 -0
  409. package/dist/node_modules/lucide-react/dist/esm/icons/monitor.js.map +1 -0
  410. package/dist/package.cjs +1 -1
  411. package/dist/package.cjs.map +1 -1
  412. package/dist/package.js +2 -2
  413. package/dist/package.js.map +1 -1
  414. package/dist/types/agent-server/core/events/conversation-state-event.d.ts +2 -19
  415. package/dist/types/agent-server/core/events/observation-event.d.ts +2 -18
  416. package/dist/types/automation.d.ts +7 -3
  417. package/dist/utils/api-error-message.d.ts +6 -2
  418. package/dist/utils/automation-catalog.cjs +2 -0
  419. package/dist/utils/automation-catalog.cjs.map +1 -0
  420. package/dist/utils/automation-catalog.d.ts +28 -0
  421. package/dist/utils/automation-catalog.js +5 -0
  422. package/dist/utils/automation-catalog.js.map +1 -0
  423. package/dist/utils/automation-timeout.d.ts +3 -2
  424. package/dist/utils/responder-deployment.d.ts +5 -1
  425. package/dist/utils/transcript-export/index.cjs +5 -5
  426. package/dist/utils/transcript-export/index.js +12 -12
  427. package/package.json +2 -2
  428. package/scripts/check-translation-completeness.cjs +1 -0
  429. package/scripts/dev-safe.mjs +15 -10
  430. package/scripts/dev-static.mjs +17 -0
  431. package/scripts/dev-with-automation.mjs +12 -14
  432. package/scripts/ingress.mjs +22 -0
  433. package/scripts/proxy-utils.mjs +157 -2
  434. package/scripts/runtime-services-info.mjs +6 -6
  435. package/scripts/static-build.mjs +0 -7
  436. package/scripts/static-server.mjs +10 -0
  437. package/build/assets/active-backend-context-mY7Gff5c.js +0 -2
  438. package/build/assets/agent-context-settings-BTUmWEzL.js +0 -1
  439. package/build/assets/agent-profiles-settings-Ilqid_R5.js +0 -1
  440. package/build/assets/agent-server-conversation-service.api-C_7YnjzP.js +0 -41
  441. package/build/assets/agent-settings-CxfT4ksO.js +0 -1
  442. package/build/assets/automation-BGP_I1RR.js +0 -1
  443. package/build/assets/automation-detail-nEflClmc.js +0 -2
  444. package/build/assets/automation-export-BO_kfqC8.js +0 -2
  445. package/build/assets/automations-list-BYncC7gv.js +0 -1
  446. package/build/assets/backend-form-modal-CKrBF80P.js +0 -1
  447. package/build/assets/browser-3QjrEr1D.js +0 -6
  448. package/build/assets/check-CrxQfJZ2.js +0 -1
  449. package/build/assets/chevron-down-D_LsyTA7.js +0 -1
  450. package/build/assets/circle-check-DZn9HkLE.js +0 -1
  451. package/build/assets/cloud-funnel-analytics-NlmDoeo2.js +0 -1
  452. package/build/assets/command-menu-CvLPs7dg.js +0 -1
  453. package/build/assets/condenser-settings-C4Y9CzQV.js +0 -1
  454. package/build/assets/conversation-D_ORtpKC.js +0 -1
  455. package/build/assets/conversation-Dpc5nmGi.js +0 -90
  456. package/build/assets/conversation-panel-D_ORtpKC.js +0 -1
  457. package/build/assets/conversation-state-store-CGRQemtx.js +0 -1
  458. package/build/assets/files-tab-4c9HFSLo.js +0 -1
  459. package/build/assets/git-provider-icon-0PqmIS_S.js +0 -1
  460. package/build/assets/home-D9JsyEmE.js +0 -1
  461. package/build/assets/home-TFhnmZLx.js +0 -1
  462. package/build/assets/index-home-D9JsyEmE.js +0 -1
  463. package/build/assets/install-server-modal-BgGRnqA0.js +0 -1
  464. package/build/assets/llm-not-configured-banner-Y4W9-sar.js +0 -27
  465. package/build/assets/llm-settings-nPwv7hKu.js +0 -1
  466. package/build/assets/loader-circle-CGD6-Vak.js +0 -1
  467. package/build/assets/manifest-1cf33a7b.js +0 -1
  468. package/build/assets/markdown-renderer-U40HF0Ak.js +0 -8
  469. package/build/assets/mcp-xDMaHzOw.js +0 -9
  470. package/build/assets/messages-CdNfZPgd.js +0 -40
  471. package/build/assets/plus-CTGLo3aa.js +0 -1
  472. package/build/assets/recommended-automations-launcher-Dru1yN46.js +0 -58
  473. package/build/assets/root-B5JXKp1P.css +0 -1
  474. package/build/assets/root-DOLLQteU.js +0 -2
  475. package/build/assets/root-layout-xmylWoew.js +0 -3
  476. package/build/assets/search-BrpWXWUi.js +0 -1
  477. package/build/assets/segmented-toggle-CZKOdIly.js +0 -1
  478. package/build/assets/settings-input-BEaTCem1.js +0 -1
  479. package/build/assets/shared-conversation-BvWtTwES.js +0 -1
  480. package/build/assets/use-agent-profiles-DmT9zxAN.js +0 -1
  481. package/build/assets/use-config-C959QcRC.js +0 -1
  482. package/build/assets/use-is-authed-BsS4XwSL.js +0 -1
  483. package/build/assets/use-llm-profiles-CdaxVpyY.js +0 -1
  484. package/build/assets/use-save-agent-profile-DGJ3-u0M.js +0 -1
  485. package/build/assets/use-settings-nav-items-DPK5sxvR.js +0 -16
  486. package/build/assets/use-tracking-COqZLobY.js +0 -1
  487. package/build/assets/utils-DsWhWn2F.js +0 -1
  488. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-Acmf1sKj.js +0 -1
  489. package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-CmzCY1BT.js +0 -1
  490. package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-C7Yh77RT.js +0 -1
  491. package/build/assets/x-Dx_JbpHA.js +0 -1
  492. /package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~f1hl7voa-BrmgjeOw.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~emdr2jt4-BrmgjeOw.js} +0 -0
@@ -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\";\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\";\nexport const AGENT_SERVER_UNKNOWN_VERSION_ERROR_CODE =\n \"AGENT_SERVER_UNKNOWN_VERSION\";\n\nexport interface AgentServerInfo extends BaseServerInfo {\n sdk_version?: string;\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 class AgentServerUnknownVersionError extends AgentServerUnavailableError {\n readonly code = AGENT_SERVER_UNKNOWN_VERSION_ERROR_CODE;\n readonly actualVersion: string | null;\n readonly requiredVersion = MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION;\n\n constructor(actualVersion: string | null) {\n const reported = actualVersion ? ` It reported \"${actualVersion}\".` : \"\";\n const message =\n `Could not determine this backend's agent-server version.${reported} ` +\n `Agent Canvas requires agent-server ${MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION} ` +\n \"or newer, but this backend did not return a valid version from \" +\n \"/server_info. Restart or rebuild the agent-server backend, then try again.\";\n super(message);\n this.name = \"AgentServerUnknownVersionError\";\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\nexport const isAgentServerUnknownVersionError = (\n error: unknown,\n): error is AgentServerUnknownVersionError =>\n error instanceof AgentServerUnknownVersionError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === AGENT_SERVER_UNKNOWN_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 normalizeAgentServerInfoVersion(version: unknown): string | null {\n if (typeof version !== \"string\") return null;\n const trimmed = version.trim();\n return trimmed || null;\n}\n\nfunction getRawAgentServerSdkVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n return normalizeAgentServerInfoVersion(serverInfo.sdk_version);\n}\n\nfunction getRawAgentServerVersion(serverInfo: AgentServerInfo): string | null {\n return (\n normalizeAgentServerInfoVersion(serverInfo.version) ??\n getRawAgentServerSdkVersion(serverInfo)\n );\n}\n\nfunction getComparableAgentServerVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n const version = getRawAgentServerVersion(serverInfo);\n if (!version || version.toLowerCase() === UNKNOWN_AGENT_SERVER_VERSION) {\n return null;\n }\n return version;\n}\n\nexport function getDisplayAgentServerVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n const version = getComparableAgentServerVersion(serverInfo);\n if (!version || !parseAgentServerVersion(version)) {\n return null;\n }\n return version;\n}\n\nexport function getDisplayAgentServerSdkVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n const version =\n getRawAgentServerSdkVersion(serverInfo) ??\n getComparableAgentServerVersion(serverInfo);\n if (!version || version.toLowerCase() === UNKNOWN_AGENT_SERVER_VERSION) {\n return null;\n }\n return version;\n}\n\nexport function getCachedAgentServerSdkVersion(\n host?: string | null,\n): string | null {\n if (!cachedAgentServerInfo) return null;\n if (host && getEffectiveLocalBackend()?.host !== host) return null;\n return getDisplayAgentServerSdkVersion(cachedAgentServerInfo);\n}\n\nexport function getCachedAgentServerVersion(\n host?: string | null,\n): string | null {\n if (!cachedAgentServerInfo) return null;\n if (host && getEffectiveLocalBackend()?.host !== host) return null;\n return getDisplayAgentServerVersion(cachedAgentServerInfo);\n}\n\nexport function 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 = getComparableAgentServerVersion(serverInfo);\n if (!actualVersion) {\n clearCachedAgentServerInfo();\n throw new AgentServerUnknownVersionError(\n getRawAgentServerVersion(serverInfo),\n );\n }\n\n const comparison = compareAgentServerVersions(\n actualVersion,\n MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION,\n );\n\n if (comparison === null) {\n clearCachedAgentServerInfo();\n throw new AgentServerUnknownVersionError(actualVersion);\n }\n\n if (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
+ {"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\";\nexport const AGENT_SERVER_UNKNOWN_VERSION_ERROR_CODE =\n \"AGENT_SERVER_UNKNOWN_VERSION\";\n\nexport interface AgentServerInfo extends BaseServerInfo {\n sdk_version?: string;\n usable_tools?: string[] | null;\n runtime_services?: unknown;\n}\n\nlet cachedAgentServerInfo: AgentServerInfo | null = null;\nlet cachedAgentServerInfoHost: string | 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 class AgentServerUnknownVersionError extends AgentServerUnavailableError {\n readonly code = AGENT_SERVER_UNKNOWN_VERSION_ERROR_CODE;\n readonly actualVersion: string | null;\n readonly requiredVersion = MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION;\n\n constructor(actualVersion: string | null) {\n const reported = actualVersion ? ` It reported \"${actualVersion}\".` : \"\";\n const message =\n `Could not determine this backend's agent-server version.${reported} ` +\n `Agent Canvas requires agent-server ${MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION} ` +\n \"or newer, but this backend did not return a valid version from \" +\n \"/server_info. Restart or rebuild the agent-server backend, then try again.\";\n super(message);\n this.name = \"AgentServerUnknownVersionError\";\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\nexport const isAgentServerUnknownVersionError = (\n error: unknown,\n): error is AgentServerUnknownVersionError =>\n error instanceof AgentServerUnknownVersionError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === AGENT_SERVER_UNKNOWN_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 cachedAgentServerInfoHost = null;\n}\n\nexport function getCachedAgentServerInfo(options?: {\n host?: string | null;\n}): AgentServerInfo | null {\n if (options?.host && options.host !== cachedAgentServerInfoHost) {\n return null;\n }\n return cachedAgentServerInfo;\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 normalizeAgentServerInfoVersion(version: unknown): string | null {\n if (typeof version !== \"string\") return null;\n const trimmed = version.trim();\n return trimmed || null;\n}\n\nfunction getRawAgentServerSdkVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n return normalizeAgentServerInfoVersion(serverInfo.sdk_version);\n}\n\nfunction getRawAgentServerVersion(serverInfo: AgentServerInfo): string | null {\n return (\n normalizeAgentServerInfoVersion(serverInfo.version) ??\n getRawAgentServerSdkVersion(serverInfo)\n );\n}\n\nfunction getComparableAgentServerVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n const version = getRawAgentServerVersion(serverInfo);\n if (!version || version.toLowerCase() === UNKNOWN_AGENT_SERVER_VERSION) {\n return null;\n }\n return version;\n}\n\nexport function getDisplayAgentServerVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n const version = getComparableAgentServerVersion(serverInfo);\n if (!version || !parseAgentServerVersion(version)) {\n return null;\n }\n return version;\n}\n\nexport function getDisplayAgentServerSdkVersion(\n serverInfo: AgentServerInfo,\n): string | null {\n const version =\n getRawAgentServerSdkVersion(serverInfo) ??\n getComparableAgentServerVersion(serverInfo);\n if (!version || version.toLowerCase() === UNKNOWN_AGENT_SERVER_VERSION) {\n return null;\n }\n return version;\n}\n\nexport function getCachedAgentServerSdkVersion(\n host?: string | null,\n): string | null {\n if (!cachedAgentServerInfo) return null;\n if (host && getEffectiveLocalBackend()?.host !== host) return null;\n return getDisplayAgentServerSdkVersion(cachedAgentServerInfo);\n}\n\nexport function getCachedAgentServerVersion(\n host?: string | null,\n): string | null {\n if (!cachedAgentServerInfo) return null;\n if (host && getEffectiveLocalBackend()?.host !== host) return null;\n return getDisplayAgentServerVersion(cachedAgentServerInfo);\n}\n\nexport function 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 = getComparableAgentServerVersion(serverInfo);\n if (!actualVersion) {\n clearCachedAgentServerInfo();\n throw new AgentServerUnknownVersionError(\n getRawAgentServerVersion(serverInfo),\n );\n }\n\n const comparison = compareAgentServerVersions(\n actualVersion,\n MINIMUM_COMPATIBLE_AGENT_SERVER_VERSION,\n );\n\n if (comparison === null) {\n clearCachedAgentServerInfo();\n throw new AgentServerUnknownVersionError(actualVersion);\n }\n\n if (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 cachedAgentServerInfoHost = clientOptions.host;\n return serverInfo;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require("../../_virtual/_rolldown/runtime.cjs");const e=require("../backend-registry/active-store.cjs"),t=require("../agent-server-client-options.cjs"),n=require("../../node_modules/axios/lib/axios.cjs"),r=require("../client-source.cjs"),i=require("../../services/telemetry.cjs"),a=require("../cloud/proxy.cjs");var o=`/api/automation`,s=n.default.create();async function c(e={}){let t=await i.getTelemetryDistinctId();return{...r.AGENT_CANVAS_CLIENT_HEADERS,...t?{[r.OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER]:t}:{},...e}}s.interceptors.request.use(async n=>{let r=await c();if(Object.entries(r).forEach(([e,t])=>{n.headers.set(e,t)}),n.baseURL)return n;let i=e.getEffectiveLocalBackend();if(!i)throw new t.NoBackendAvailableError;n.baseURL=i.host;let a=i.apiKey?.trim();return a&&n.headers.set(`X-Session-API-Key`,a),n});function l(e){return typeof e==`string`&&e.trim()||null}function u(e){return typeof e==`string`?l(e):l(e.sdk_version)??l(e.version)}function d(e,t){let n=new URLSearchParams;return n.set(`limit`,String(e)),n.set(`offset`,String(t)),n.toString()}function f(e){return e.trigger.type===`event`?{type:`event`,source:e.trigger.source,on:e.trigger.on,...e.trigger.filter&&{filter:e.trigger.filter}}:{type:`cron`,schedule:e.trigger.schedule,timezone:e.timezone??e.trigger.timezone??`UTC`}}function p(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?`pending.${crypto.randomUUID()}`:`pending.${Date.now()}.${Math.random().toString(36).slice(2,10)}`}function m(e){if(!e.prompt)throw Error(`An automation prompt is required for import.`);let t=e.repository?[{url:e.repository,...e.branch&&{ref:e.branch},...!e.repository.includes(`://`)&&!e.repository.startsWith(`git@`)&&{provider:`github`}}]:void 0;return{path:`${o}/v1/preset/${e.plugins?.length?`plugin`:`prompt`}`,body:{name:e.name,prompt:e.prompt,trigger:{type:`event`,source:`agent-canvas-import`,on:p()},...e.model&&{model:e.model},...t&&{repos:t},...e.plugins?.length&&{plugins:e.plugins.map(e=>({source:e}))},...e.timeout!=null&&{timeout:e.timeout}}}}async function h(e){let t=e.apiKey.trim();return{baseURL:e.host,headers:await c(t?{"X-Session-API-Key":t}:{})}}async function g(e){return c(e.orgId?{"X-Org-Id":e.orgId}:{})}var _=class t{static async syncTelemetryConsent(t=i.getTelemetryConsent()){if(e.getActiveBackend().backend.kind!==`local`)return;let n=await i.getTelemetryDistinctIdForConsentSync();await s.post(`${o}/v1/telemetry/consent`,{consent_granted:t===`granted`,frontend_distinct_id:n},{timeout:5e3}),t!==`granted`&&n&&i.clearPendingLocalTelemetryRevocation(n)}static async getSdkVersion(){let t=e.getActiveBackend(),n=`${o}/sdk-version`;try{let e;if(t.backend.kind===`cloud`)e=await a.callCloudProxy({backend:t.backend,method:`GET`,path:n,headers:await g(t),timeoutSeconds:5});else{let{data:t}=await s.get(n,{timeout:5e3});e=t}return u(e)}catch{return null}}static async listAutomations(t={}){let{limit:n=50,offset:r=0}=t,i=e.getActiveBackend().backend;if(i.kind===`cloud`)return a.callCloudProxy({backend:i,method:`GET`,path:`${o}/v1?${d(n,r)}`,headers:await c()});let{data:l}=await s.get(`${o}/v1`,{params:{limit:n,offset:r}});return l}static async getAutomations(e=50,n=0){return t.listAutomations({limit:e,offset:n})}static async getAutomation(t){let n=e.getActiveBackend().backend,r=`${o}/v1/${encodeURIComponent(t)}`;if(n.kind===`cloud`)return a.callCloudProxy({backend:n,method:`GET`,path:r,headers:await c()});let{data:i}=await s.get(r);return i}static async createAutomation(t){let n=e.getActiveBackend(),{path:r,body:i}=m(t),c;if(n.backend.kind===`cloud`)c=await a.callCloudProxy({backend:n.backend,method:`POST`,path:r,body:i,headers:await g(n)});else{let{data:e}=await s.post(r,i,await h(n.backend));c=e}let l=`${o}/v1/${encodeURIComponent(c.id)}`,u={trigger:f(t),enabled:!1};try{if(n.backend.kind===`cloud`)return await a.callCloudProxy({backend:n.backend,method:`PATCH`,path:l,body:u,headers:await g(n)});let{data:e}=await s.patch(l,u,await h(n.backend));return e}catch(e){try{n.backend.kind===`cloud`?await a.callCloudProxy({backend:n.backend,method:`DELETE`,path:l,headers:await g(n)}):await s.delete(l,await h(n.backend))}catch(t){throw AggregateError([e,t],`Failed to disable the imported automation and clean it up.`)}throw e}}static async updateAutomation(t,n){let r=e.getActiveBackend().backend,i=`${o}/v1/${encodeURIComponent(t)}`;if(r.kind===`cloud`)return a.callCloudProxy({backend:r,method:`PATCH`,path:i,body:n,headers:await c()});let{data:l}=await s.patch(i,n);return l}static async deleteAutomation(t){let n=e.getActiveBackend().backend,r=`${o}/v1/${encodeURIComponent(t)}`;if(n.kind===`cloud`){await a.callCloudProxy({backend:n,method:`DELETE`,path:r,headers:await c()});return}await s.delete(r)}static async dispatchAutomation(t){let n=e.getActiveBackend().backend,r=`${o}/v1/${encodeURIComponent(t)}/dispatch`;if(n.kind===`cloud`)return a.callCloudProxy({backend:n,method:`POST`,path:r,headers:await c()});let{data:i}=await s.post(r);return i}static async listAutomationRuns(t,n={}){let{limit:r=50,offset:i=0}=n,l=e.getActiveBackend().backend,u=`${o}/v1/${encodeURIComponent(t)}/runs`;if(l.kind===`cloud`)return a.callCloudProxy({backend:l,method:`GET`,path:`${u}?${d(r,i)}`,headers:await c()});let{data:f}=await s.get(u,{params:{limit:r,offset:i}});return f}static async getAutomationRuns(e,n=50,r=0){return t.listAutomationRuns(e,{limit:n,offset:r})}static async toggleAutomation(e,n){return t.updateAutomation(e,{enabled:n})}static async downloadTarball(t,n){let r=e.getActiveBackend().backend,i=`${o}/v1/${encodeURIComponent(t)}/tarball`,l;if(r.kind===`cloud`)l=await a.callCloudProxy({backend:r,method:`GET`,path:i,responseType:`blob`,headers:await c()});else{let{data:e}=await s.get(i,{responseType:`blob`});l=e}let u=URL.createObjectURL(l),d=document.createElement(`a`);d.href=u,d.download=`${n}.tar`,d.click(),URL.revokeObjectURL(u)}static async checkHealth(){let t=e.getActiveBackend().backend,n=`${o}/health`;try{if(t.kind===`cloud`)return await a.callCloudProxy({backend:t,method:`GET`,path:n,timeoutSeconds:5,headers:await c()});let{data:e}=await s.get(n,{timeout:5e3});return e}catch{return{status:`error`}}}};exports.default=_;
1
+ require("../../_virtual/_rolldown/runtime.cjs");const e=require("../backend-registry/active-store.cjs"),t=require("../agent-server-client-options.cjs"),n=require("../../node_modules/axios/lib/axios.cjs"),r=require("../client-source.cjs"),i=require("../../services/telemetry.cjs"),a=require("../cloud/proxy.cjs"),o=require("../../manifests/automation-interface.cjs"),s=require("../../manifests/automation-setup.cjs");var c=`/api/automation`,l=n.default.create();async function u(e={}){let t=await i.getTelemetryDistinctId();return{...r.AGENT_CANVAS_CLIENT_HEADERS,...t?{[r.OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER]:t}:{},...e}}l.interceptors.request.use(async n=>{let r=await u();if(Object.entries(r).forEach(([e,t])=>{n.headers.set(e,t)}),n.baseURL)return n;let i=e.getEffectiveLocalBackend();if(!i)throw new t.NoBackendAvailableError;n.baseURL=i.host;let a=i.apiKey?.trim();return a&&n.headers.set(`X-Session-API-Key`,a),n});function d(e){return typeof e==`string`&&e.trim()||null}function f(e){return typeof e==`string`?d(e):d(e.sdk_version)??d(e.version)}function p(e,t){let n=new URLSearchParams;return n.set(`limit`,String(e)),n.set(`offset`,String(t)),n.toString()}function m(e){return e.trigger.type===`event`?{type:`event`,source:e.trigger.source,on:e.trigger.on,...e.trigger.filter&&{filter:e.trigger.filter}}:{type:`cron`,schedule:e.trigger.schedule,timezone:e.timezone??e.trigger.timezone??`UTC`}}function h(){return typeof crypto<`u`&&typeof crypto.randomUUID==`function`?`pending.${crypto.randomUUID()}`:`pending.${Date.now()}.${Math.random().toString(36).slice(2,10)}`}function g(e){if(!e.prompt)throw Error(`An automation prompt is required for import.`);let{importDefaults:t}=o.getImportExportSpec(),n=e.repository?[{url:e.repository,...e.branch&&{ref:e.branch},...!e.repository.includes(`://`)&&!e.repository.startsWith(`git@`)&&{provider:t.repoProvider}}]:void 0;return{path:`${c}${o.getAutomationEndpoint(e.plugins?.length?`createPlugin`:`createPrompt`)}`,body:{name:e.name,prompt:e.prompt,trigger:{type:`event`,source:t.placeholderEventSource,on:h()},...e.model&&{model:e.model},...n&&{repos:n},...e.plugins?.length&&{plugins:e.plugins.map(e=>({source:e}))},...e.timeout!=null&&{timeout:e.timeout}}}}async function _(e){let t=e.apiKey.trim();return{baseURL:e.host,headers:await u(t?{"X-Session-API-Key":t}:{})}}async function v(e){return u(e.orgId?{"X-Org-Id":e.orgId}:{})}var y=class t{static async syncTelemetryConsent(t=i.getTelemetryConsent()){if(e.getActiveBackend().backend.kind!==`local`)return;let n=await i.getTelemetryDistinctIdForConsentSync();await l.post(`${c}/v1/telemetry/consent`,{consent_granted:t===`granted`,frontend_distinct_id:n},{timeout:5e3}),t!==`granted`&&n&&i.clearPendingLocalTelemetryRevocation(n)}static async getSdkVersion(){let t=e.getActiveBackend(),n=`${c}/sdk-version`;try{let e;if(t.backend.kind===`cloud`)e=await a.callCloudProxy({backend:t.backend,method:`GET`,path:n,headers:await v(t),timeoutSeconds:5});else{let{data:t}=await l.get(n,{timeout:5e3});e=t}return f(e)}catch{return null}}static async listAutomations(t={}){let{limit:n=50,offset:r=0}=t,i=e.getActiveBackend().backend;if(i.kind===`cloud`)return a.callCloudProxy({backend:i,method:`GET`,path:`${c}${o.getAutomationEndpoint(`list`)}?${p(n,r)}`,headers:await u()});let{data:s}=await l.get(`${c}${o.getAutomationEndpoint(`list`)}`,{params:{limit:n,offset:r}});return s}static async getAutomations(e=50,n=0){return t.listAutomations({limit:e,offset:n})}static async getAutomation(t){let n=e.getActiveBackend().backend,r=`${c}${o.getAutomationIdEndpoint(`detail`,t)}`;if(n.kind===`cloud`)return a.callCloudProxy({backend:n,method:`GET`,path:r,headers:await u()});let{data:i}=await l.get(r);return i}static async createAutomation(t){let n=e.getActiveBackend(),{path:r,body:i}=g(t),s;if(n.backend.kind===`cloud`)s=await a.callCloudProxy({backend:n.backend,method:`POST`,path:r,body:i,headers:await v(n)});else{let{data:e}=await l.post(r,i,await _(n.backend));s=e}let u=`${c}${o.getAutomationIdEndpoint(`detail`,s.id)}`,d={trigger:m(t),enabled:!1};try{if(n.backend.kind===`cloud`)return await a.callCloudProxy({backend:n.backend,method:`PATCH`,path:u,body:d,headers:await v(n)});let{data:e}=await l.patch(u,d,await _(n.backend));return e}catch(e){try{n.backend.kind===`cloud`?await a.callCloudProxy({backend:n.backend,method:`DELETE`,path:u,headers:await v(n)}):await l.delete(u,await _(n.backend))}catch(t){throw AggregateError([e,t],`Failed to disable the imported automation and clean it up.`)}throw e}}static async updateAutomation(t,n){let r=e.getActiveBackend().backend,i=`${c}${o.getAutomationIdEndpoint(`detail`,t)}`;if(r.kind===`cloud`)return a.callCloudProxy({backend:r,method:`PATCH`,path:i,body:n,headers:await u()});let{data:s}=await l.patch(i,n);return s}static async deleteAutomation(t){let n=e.getActiveBackend().backend,r=`${c}${o.getAutomationIdEndpoint(`detail`,t)}`;if(n.kind===`cloud`){await a.callCloudProxy({backend:n,method:`DELETE`,path:r,headers:await u()});return}await l.delete(r)}static async dispatchAutomation(t){let n=e.getActiveBackend().backend,r=`${c}${o.getAutomationIdEndpoint(`dispatch`,t)}`;if(n.kind===`cloud`)return a.callCloudProxy({backend:n,method:`POST`,path:r,headers:await u()});let{data:i}=await l.post(r);return i}static async listAutomationRuns(t,n={}){let{limit:r=50,offset:i=0}=n,s=e.getActiveBackend().backend,d=`${c}${o.getAutomationIdEndpoint(`runs`,t)}`;if(s.kind===`cloud`)return a.callCloudProxy({backend:s,method:`GET`,path:`${d}?${p(r,i)}`,headers:await u()});let{data:f}=await l.get(d,{params:{limit:r,offset:i}});return f}static async getAutomationRuns(e,n=50,r=0){return t.listAutomationRuns(e,{limit:n,offset:r})}static async toggleAutomation(e,n){return t.updateAutomation(e,{enabled:n})}static async downloadTarball(t,n){let r=e.getActiveBackend().backend,i=`${c}${o.getAutomationIdEndpoint(`tarball`,t)}`,s;if(r.kind===`cloud`)s=await a.callCloudProxy({backend:r,method:`GET`,path:i,responseType:`blob`,headers:await u()});else{let{data:e}=await l.get(i,{responseType:`blob`});s=e}let d=URL.createObjectURL(s),f=document.createElement(`a`);f.href=d,f.download=`${n}.tar`,f.click(),URL.revokeObjectURL(d)}static async getCapabilities(){let t=e.getActiveBackend().backend,n=`${c}${o.getAutomationEndpoint(`capabilities`)}`;if(t.kind===`cloud`)return a.callCloudProxy({backend:t,method:`GET`,path:n,headers:await u()});let{data:r}=await l.get(n);return r}static async validateDraft(t){let n=e.getActiveBackend().backend,r=`${c}${o.getAutomationEndpoint(`validate`)}`;if(n.kind===`cloud`)return a.callCloudProxy({backend:n,method:`POST`,path:r,body:t,headers:await u()});let{data:i}=await l.post(r,t);return i}static async createAutomationDraft(t){let n=e.getActiveBackend().backend,r=`${c}${s.AUTOMATION_CREATE_ENDPOINT}`;if(n.kind===`cloud`)return a.callCloudProxy({backend:n,method:`POST`,path:r,body:t,headers:await u()});let{data:i}=await l.post(r,t);return i}static async checkHealth(){let t=e.getActiveBackend().backend,n=`${c}${o.getAutomationEndpoint(`health`)}`;try{if(t.kind===`cloud`)return await a.callCloudProxy({backend:t,method:`GET`,path:n,timeoutSeconds:5,headers:await u()});let{data:e}=await l.get(n,{timeout:5e3});return e}catch{return{status:`error`}}}};exports.default=y;
2
2
  //# sourceMappingURL=automation-service.api.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"automation-service.api.cjs","names":[],"sources":["../../../src/api/automation-service/automation-service.api.ts"],"sourcesContent":["import axios from \"axios\";\nimport {\n clearPendingLocalTelemetryRevocation,\n getTelemetryConsent,\n getTelemetryDistinctId,\n getTelemetryDistinctIdForConsentSync,\n type TelemetryConsent,\n} from \"#/services/telemetry\";\nimport type {\n Automation,\n AutomationRun,\n AutomationSpec,\n AutomationTrigger,\n AutomationsResponse,\n AutomationRunsResponse,\n} from \"#/types/automation\";\nimport type { Backend, ResolvedActiveBackend } from \"../backend-registry/types\";\nimport {\n getActiveBackend,\n getEffectiveLocalBackend,\n} from \"../backend-registry/active-store\";\nimport { NoBackendAvailableError } from \"../agent-server-client-options\";\nimport { callCloudProxy } from \"../cloud/proxy\";\nimport {\n AGENT_CANVAS_CLIENT_HEADERS,\n OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER,\n} from \"../client-source\";\n\nconst AUTOMATION_BASE_PATH = \"/api/automation\";\n\nexport interface AutomationHealthResponse {\n status: \"ok\" | \"error\";\n message?: string;\n}\n\ntype AutomationSdkVersionResponse =\n | string\n | {\n sdk_version?: unknown;\n version?: unknown;\n };\n\n// Local automation calls go to the automation sidecar that\n// `scripts/dev-with-automation.mjs` mounts behind the local agent-server.\n// Both backends use the same session API key and the same `X-Session-API-Key`\n// header for consistency.\nconst localAutomationAxios = axios.create();\n\nasync function buildAutomationRequestHeaders(\n extraHeaders: Record<string, string> = {},\n): Promise<Record<string, string>> {\n const telemetryDistinctId = await getTelemetryDistinctId();\n return {\n ...AGENT_CANVAS_CLIENT_HEADERS,\n ...(telemetryDistinctId\n ? { [OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER]: telemetryDistinctId }\n : {}),\n ...extraHeaders,\n };\n}\n\nlocalAutomationAxios.interceptors.request.use(async (config) => {\n const requestHeaders = await buildAutomationRequestHeaders();\n Object.entries(requestHeaders).forEach(([name, value]) => {\n config.headers.set(name, value);\n });\n\n // Import uses an explicit baseURL/header pair so its POST, PATCH, and\n // cleanup stay pinned to the backend selected when the mutation started.\n if (config.baseURL) return config;\n\n // Resolve the local backend on every call so it tracks the\n // currently-active local backend (and any host/key edits made via the\n // manage-backends UI), rather than freezing whatever value the\n // agent-server-config produced at module load time.\n // Using the backend registry (rather than the build-time VITE_SESSION_API_KEY\n // env var) ensures the published npm package picks up the runtime-injected\n // session key that scripts/static-server.mjs seeds into localStorage, fixing\n // the 401 errors reported in issue #829.\n const backend = getEffectiveLocalBackend();\n if (!backend) throw new NoBackendAvailableError();\n // eslint-disable-next-line no-param-reassign\n config.baseURL = backend.host;\n\n const apiKey = backend.apiKey?.trim();\n if (apiKey) {\n config.headers.set(\"X-Session-API-Key\", apiKey);\n }\n return config;\n});\n\nfunction normalizeAutomationSdkVersion(version: unknown): string | null {\n if (typeof version !== \"string\") return null;\n const trimmed = version.trim();\n return trimmed || null;\n}\n\nfunction getAutomationSdkVersionFromResponse(\n response: AutomationSdkVersionResponse,\n): string | null {\n if (typeof response === \"string\") {\n return normalizeAutomationSdkVersion(response);\n }\n return (\n normalizeAutomationSdkVersion(response.sdk_version) ??\n normalizeAutomationSdkVersion(response.version)\n );\n}\n\nfunction buildPaginationQuery(limit: number, offset: number): string {\n const params = new URLSearchParams();\n params.set(\"limit\", String(limit));\n params.set(\"offset\", String(offset));\n return params.toString();\n}\n\nfunction buildImportedTrigger(spec: AutomationSpec): AutomationTrigger {\n if (spec.trigger.type === \"event\") {\n return {\n type: \"event\",\n source: spec.trigger.source,\n on: spec.trigger.on,\n ...(spec.trigger.filter && { filter: spec.trigger.filter }),\n };\n }\n\n return {\n type: \"cron\",\n schedule: spec.trigger.schedule,\n timezone: spec.timezone ?? spec.trigger.timezone ?? \"UTC\",\n };\n}\n\nfunction generatePendingImportEvent(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return `pending.${crypto.randomUUID()}`;\n }\n return `pending.${Date.now()}.${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction buildCreateAutomationRequest(spec: AutomationSpec) {\n if (!spec.prompt) {\n throw new Error(\"An automation prompt is required for import.\");\n }\n\n const repos = spec.repository\n ? [\n {\n url: spec.repository,\n ...(spec.branch && { ref: spec.branch }),\n ...(!spec.repository.includes(\"://\") &&\n !spec.repository.startsWith(\"git@\") && { provider: \"github\" }),\n },\n ]\n : undefined;\n\n return {\n path: `${AUTOMATION_BASE_PATH}/v1/preset/${spec.plugins?.length ? \"plugin\" : \"prompt\"}`,\n body: {\n name: spec.name,\n prompt: spec.prompt,\n // Preset creation defaults to enabled. A unique event trigger keeps the\n // new record inert until the real trigger and disabled state are applied\n // together in the follow-up PATCH.\n trigger: {\n type: \"event\",\n source: \"agent-canvas-import\",\n on: generatePendingImportEvent(),\n },\n ...(spec.model && { model: spec.model }),\n ...(repos && { repos }),\n ...(spec.plugins?.length && {\n plugins: spec.plugins.map((source) => ({ source })),\n }),\n ...(spec.timeout != null && { timeout: spec.timeout }),\n },\n };\n}\n\nasync function buildPinnedLocalConfig(backend: Backend) {\n const apiKey = backend.apiKey.trim();\n return {\n baseURL: backend.host,\n headers: await buildAutomationRequestHeaders(\n apiKey ? { \"X-Session-API-Key\": apiKey } : {},\n ),\n };\n}\n\nasync function buildPinnedCloudHeaders(active: ResolvedActiveBackend) {\n return buildAutomationRequestHeaders(\n active.orgId ? { \"X-Org-Id\": active.orgId } : {},\n );\n}\n\nclass AutomationService {\n static async syncTelemetryConsent(\n consent: TelemetryConsent = getTelemetryConsent(),\n ): Promise<void> {\n const active = getActiveBackend();\n if (active.backend.kind !== \"local\") return;\n\n const frontendDistinctId = await getTelemetryDistinctIdForConsentSync();\n await localAutomationAxios.post(\n `${AUTOMATION_BASE_PATH}/v1/telemetry/consent`,\n {\n consent_granted: consent === \"granted\",\n frontend_distinct_id: frontendDistinctId,\n },\n { timeout: 5000 },\n );\n if (consent !== \"granted\" && frontendDistinctId) {\n clearPendingLocalTelemetryRevocation(frontendDistinctId);\n }\n }\n\n static async getSdkVersion(): Promise<string | null> {\n const active = getActiveBackend();\n const path = `${AUTOMATION_BASE_PATH}/sdk-version`;\n\n try {\n let response: AutomationSdkVersionResponse;\n if (active.backend.kind === \"cloud\") {\n response = await callCloudProxy<AutomationSdkVersionResponse>({\n backend: active.backend,\n method: \"GET\",\n path,\n headers: await buildPinnedCloudHeaders(active),\n timeoutSeconds: 5,\n });\n } else {\n const { data } =\n await localAutomationAxios.get<AutomationSdkVersionResponse>(path, {\n timeout: 5000,\n });\n response = data;\n }\n\n return getAutomationSdkVersionFromResponse(response);\n } catch {\n return null;\n }\n }\n\n static async listAutomations(\n params: { limit?: number; offset?: number } = {},\n ): Promise<AutomationsResponse> {\n const { limit = 50, offset = 0 } = params;\n const active = getActiveBackend().backend;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<AutomationsResponse>({\n backend: active,\n method: \"GET\",\n path: `${AUTOMATION_BASE_PATH}/v1?${buildPaginationQuery(limit, offset)}`,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.get<AutomationsResponse>(\n `${AUTOMATION_BASE_PATH}/v1`,\n { params: { limit, offset } },\n );\n return data;\n }\n\n static async getAutomations(\n limit = 50,\n offset = 0,\n ): Promise<AutomationsResponse> {\n return AutomationService.listAutomations({ limit, offset });\n }\n\n static async getAutomation(id: string): Promise<Automation> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(id)}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<Automation>({\n backend: active,\n method: \"GET\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.get<Automation>(path);\n return data;\n }\n\n static async createAutomation(spec: AutomationSpec): Promise<Automation> {\n const active = getActiveBackend();\n const { path, body } = buildCreateAutomationRequest(spec);\n\n let created: Automation;\n if (active.backend.kind === \"cloud\") {\n created = await callCloudProxy<Automation>({\n backend: active.backend,\n method: \"POST\",\n path,\n body,\n headers: await buildPinnedCloudHeaders(active),\n });\n } else {\n const { data } = await localAutomationAxios.post<Automation>(\n path,\n body,\n await buildPinnedLocalConfig(active.backend),\n );\n created = data;\n }\n\n const updatePath = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(created.id)}`;\n const updateBody: Partial<Automation> = {\n trigger: buildImportedTrigger(spec),\n enabled: false,\n };\n\n try {\n if (active.backend.kind === \"cloud\") {\n return await callCloudProxy<Automation>({\n backend: active.backend,\n method: \"PATCH\",\n path: updatePath,\n body: updateBody,\n headers: await buildPinnedCloudHeaders(active),\n });\n }\n\n const { data } = await localAutomationAxios.patch<Automation>(\n updatePath,\n updateBody,\n await buildPinnedLocalConfig(active.backend),\n );\n return data;\n } catch (updateError) {\n try {\n if (active.backend.kind === \"cloud\") {\n await callCloudProxy<unknown>({\n backend: active.backend,\n method: \"DELETE\",\n path: updatePath,\n headers: await buildPinnedCloudHeaders(active),\n });\n } else {\n await localAutomationAxios.delete(\n updatePath,\n await buildPinnedLocalConfig(active.backend),\n );\n }\n } catch (cleanupError) {\n throw new AggregateError(\n [updateError, cleanupError],\n \"Failed to disable the imported automation and clean it up.\",\n );\n }\n throw updateError;\n }\n }\n\n static async updateAutomation(\n id: string,\n body: Partial<Automation>,\n ): Promise<Automation> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(id)}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<Automation>({\n backend: active,\n method: \"PATCH\",\n path,\n body: body as Record<string, unknown>,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.patch<Automation>(path, body);\n return data;\n }\n\n static async deleteAutomation(id: string): Promise<void> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(id)}`;\n\n if (active.kind === \"cloud\") {\n await callCloudProxy<unknown>({\n backend: active,\n method: \"DELETE\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n return;\n }\n\n await localAutomationAxios.delete(path);\n }\n\n static async dispatchAutomation(id: string): Promise<AutomationRun> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(id)}/dispatch`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<AutomationRun>({\n backend: active,\n method: \"POST\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.post<AutomationRun>(path);\n return data;\n }\n\n static async listAutomationRuns(\n id: string,\n params: { limit?: number; offset?: number } = {},\n ): Promise<AutomationRunsResponse> {\n const { limit = 50, offset = 0 } = params;\n const active = getActiveBackend().backend;\n const basePath = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(id)}/runs`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<AutomationRunsResponse>({\n backend: active,\n method: \"GET\",\n path: `${basePath}?${buildPaginationQuery(limit, offset)}`,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.get<AutomationRunsResponse>(\n basePath,\n { params: { limit, offset } },\n );\n return data;\n }\n\n static async getAutomationRuns(\n id: string,\n limit = 50,\n offset = 0,\n ): Promise<AutomationRunsResponse> {\n return AutomationService.listAutomationRuns(id, { limit, offset });\n }\n\n static async toggleAutomation(\n id: string,\n enabled: boolean,\n ): Promise<Automation> {\n return AutomationService.updateAutomation(id, { enabled });\n }\n\n static async downloadTarball(id: string, name: string): Promise<void> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}/v1/${encodeURIComponent(id)}/tarball`;\n\n let blob: Blob;\n if (active.kind === \"cloud\") {\n blob = await callCloudProxy<Blob>({\n backend: active,\n method: \"GET\",\n path,\n responseType: \"blob\",\n headers: await buildAutomationRequestHeaders(),\n });\n } else {\n const { data } = await localAutomationAxios.get<Blob>(path, {\n responseType: \"blob\",\n });\n blob = data;\n }\n\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${name}.tar`;\n a.click();\n URL.revokeObjectURL(url);\n }\n\n static async checkHealth(): Promise<AutomationHealthResponse> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}/health`;\n\n try {\n if (active.kind === \"cloud\") {\n const response = await callCloudProxy<AutomationHealthResponse>({\n backend: active,\n method: \"GET\",\n path,\n // Fail fast, matching the local branch's 5s timeout below.\n timeoutSeconds: 5,\n headers: await buildAutomationRequestHeaders(),\n });\n return response;\n }\n\n const { data } = await localAutomationAxios.get<AutomationHealthResponse>(\n path,\n { timeout: 5000 },\n );\n return data;\n } catch {\n return { status: \"error\" };\n }\n }\n}\n\nexport default AutomationService;\n"],"mappings":"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"}
1
+ {"version":3,"file":"automation-service.api.cjs","names":[],"sources":["../../../src/api/automation-service/automation-service.api.ts"],"sourcesContent":["import axios from \"axios\";\nimport {\n clearPendingLocalTelemetryRevocation,\n getTelemetryConsent,\n getTelemetryDistinctId,\n getTelemetryDistinctIdForConsentSync,\n type TelemetryConsent,\n} from \"#/services/telemetry\";\nimport type {\n Automation,\n AutomationRun,\n AutomationSpec,\n AutomationTrigger,\n AutomationsResponse,\n AutomationRunsResponse,\n} from \"#/types/automation\";\nimport { AUTOMATION_CREATE_ENDPOINT } from \"#/manifests/automation-setup\";\nimport {\n getAutomationEndpoint,\n getAutomationIdEndpoint,\n getImportExportSpec,\n} from \"#/manifests/automation-interface\";\nimport type {\n DeploymentCapabilities,\n SetupRequestBody,\n ValidateDraftResponse,\n} from \"#/manifests/types\";\nimport type { Backend, ResolvedActiveBackend } from \"../backend-registry/types\";\nimport {\n getActiveBackend,\n getEffectiveLocalBackend,\n} from \"../backend-registry/active-store\";\nimport { NoBackendAvailableError } from \"../agent-server-client-options\";\nimport { callCloudProxy } from \"../cloud/proxy\";\nimport {\n AGENT_CANVAS_CLIENT_HEADERS,\n OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER,\n} from \"../client-source\";\n\nconst AUTOMATION_BASE_PATH = \"/api/automation\";\n\nexport interface AutomationHealthResponse {\n status: \"ok\" | \"error\";\n message?: string;\n}\n\ntype AutomationSdkVersionResponse =\n | string\n | {\n sdk_version?: unknown;\n version?: unknown;\n };\n\n// Local automation calls go to the automation sidecar that\n// `scripts/dev-with-automation.mjs` mounts behind the local agent-server.\n// Both backends use the same session API key and the same `X-Session-API-Key`\n// header for consistency.\nconst localAutomationAxios = axios.create();\n\nasync function buildAutomationRequestHeaders(\n extraHeaders: Record<string, string> = {},\n): Promise<Record<string, string>> {\n const telemetryDistinctId = await getTelemetryDistinctId();\n return {\n ...AGENT_CANVAS_CLIENT_HEADERS,\n ...(telemetryDistinctId\n ? { [OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER]: telemetryDistinctId }\n : {}),\n ...extraHeaders,\n };\n}\n\nlocalAutomationAxios.interceptors.request.use(async (config) => {\n const requestHeaders = await buildAutomationRequestHeaders();\n Object.entries(requestHeaders).forEach(([name, value]) => {\n config.headers.set(name, value);\n });\n\n // Import uses an explicit baseURL/header pair so its POST, PATCH, and\n // cleanup stay pinned to the backend selected when the mutation started.\n if (config.baseURL) return config;\n\n // Resolve the local backend on every call so it tracks the\n // currently-active local backend (and any host/key edits made via the\n // manage-backends UI), rather than freezing whatever value the\n // agent-server-config produced at module load time.\n // Using the backend registry (rather than the build-time VITE_SESSION_API_KEY\n // env var) ensures the published npm package picks up the runtime-injected\n // session key that scripts/static-server.mjs seeds into localStorage, fixing\n // the 401 errors reported in issue #829.\n const backend = getEffectiveLocalBackend();\n if (!backend) throw new NoBackendAvailableError();\n // eslint-disable-next-line no-param-reassign\n config.baseURL = backend.host;\n\n const apiKey = backend.apiKey?.trim();\n if (apiKey) {\n config.headers.set(\"X-Session-API-Key\", apiKey);\n }\n return config;\n});\n\nfunction normalizeAutomationSdkVersion(version: unknown): string | null {\n if (typeof version !== \"string\") return null;\n const trimmed = version.trim();\n return trimmed || null;\n}\n\nfunction getAutomationSdkVersionFromResponse(\n response: AutomationSdkVersionResponse,\n): string | null {\n if (typeof response === \"string\") {\n return normalizeAutomationSdkVersion(response);\n }\n return (\n normalizeAutomationSdkVersion(response.sdk_version) ??\n normalizeAutomationSdkVersion(response.version)\n );\n}\n\nfunction buildPaginationQuery(limit: number, offset: number): string {\n const params = new URLSearchParams();\n params.set(\"limit\", String(limit));\n params.set(\"offset\", String(offset));\n return params.toString();\n}\n\nfunction buildImportedTrigger(spec: AutomationSpec): AutomationTrigger {\n if (spec.trigger.type === \"event\") {\n return {\n type: \"event\",\n source: spec.trigger.source,\n on: spec.trigger.on,\n ...(spec.trigger.filter && { filter: spec.trigger.filter }),\n };\n }\n\n return {\n type: \"cron\",\n schedule: spec.trigger.schedule,\n timezone: spec.timezone ?? spec.trigger.timezone ?? \"UTC\",\n };\n}\n\nfunction generatePendingImportEvent(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return `pending.${crypto.randomUUID()}`;\n }\n return `pending.${Date.now()}.${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction buildCreateAutomationRequest(spec: AutomationSpec) {\n if (!spec.prompt) {\n throw new Error(\"An automation prompt is required for import.\");\n }\n\n const { importDefaults } = getImportExportSpec();\n const repos = spec.repository\n ? [\n {\n url: spec.repository,\n ...(spec.branch && { ref: spec.branch }),\n ...(!spec.repository.includes(\"://\") &&\n !spec.repository.startsWith(\"git@\") && {\n provider: importDefaults.repoProvider,\n }),\n },\n ]\n : undefined;\n\n return {\n path: `${AUTOMATION_BASE_PATH}${getAutomationEndpoint(\n spec.plugins?.length ? \"createPlugin\" : \"createPrompt\",\n )}`,\n body: {\n name: spec.name,\n prompt: spec.prompt,\n // Preset creation defaults to enabled. A unique event trigger keeps the\n // new record inert until the real trigger and disabled state are applied\n // together in the follow-up PATCH.\n trigger: {\n type: \"event\",\n source: importDefaults.placeholderEventSource,\n on: generatePendingImportEvent(),\n },\n ...(spec.model && { model: spec.model }),\n ...(repos && { repos }),\n ...(spec.plugins?.length && {\n plugins: spec.plugins.map((source) => ({ source })),\n }),\n ...(spec.timeout != null && { timeout: spec.timeout }),\n },\n };\n}\n\nasync function buildPinnedLocalConfig(backend: Backend) {\n const apiKey = backend.apiKey.trim();\n return {\n baseURL: backend.host,\n headers: await buildAutomationRequestHeaders(\n apiKey ? { \"X-Session-API-Key\": apiKey } : {},\n ),\n };\n}\n\nasync function buildPinnedCloudHeaders(active: ResolvedActiveBackend) {\n return buildAutomationRequestHeaders(\n active.orgId ? { \"X-Org-Id\": active.orgId } : {},\n );\n}\n\nclass AutomationService {\n static async syncTelemetryConsent(\n consent: TelemetryConsent = getTelemetryConsent(),\n ): Promise<void> {\n const active = getActiveBackend();\n if (active.backend.kind !== \"local\") return;\n\n const frontendDistinctId = await getTelemetryDistinctIdForConsentSync();\n await localAutomationAxios.post(\n `${AUTOMATION_BASE_PATH}/v1/telemetry/consent`,\n {\n consent_granted: consent === \"granted\",\n frontend_distinct_id: frontendDistinctId,\n },\n { timeout: 5000 },\n );\n if (consent !== \"granted\" && frontendDistinctId) {\n clearPendingLocalTelemetryRevocation(frontendDistinctId);\n }\n }\n\n static async getSdkVersion(): Promise<string | null> {\n const active = getActiveBackend();\n const path = `${AUTOMATION_BASE_PATH}/sdk-version`;\n\n try {\n let response: AutomationSdkVersionResponse;\n if (active.backend.kind === \"cloud\") {\n response = await callCloudProxy<AutomationSdkVersionResponse>({\n backend: active.backend,\n method: \"GET\",\n path,\n headers: await buildPinnedCloudHeaders(active),\n timeoutSeconds: 5,\n });\n } else {\n const { data } =\n await localAutomationAxios.get<AutomationSdkVersionResponse>(path, {\n timeout: 5000,\n });\n response = data;\n }\n\n return getAutomationSdkVersionFromResponse(response);\n } catch {\n return null;\n }\n }\n\n static async listAutomations(\n params: { limit?: number; offset?: number } = {},\n ): Promise<AutomationsResponse> {\n const { limit = 50, offset = 0 } = params;\n const active = getActiveBackend().backend;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<AutomationsResponse>({\n backend: active,\n method: \"GET\",\n path: `${AUTOMATION_BASE_PATH}${getAutomationEndpoint(\"list\")}?${buildPaginationQuery(limit, offset)}`,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.get<AutomationsResponse>(\n `${AUTOMATION_BASE_PATH}${getAutomationEndpoint(\"list\")}`,\n { params: { limit, offset } },\n );\n return data;\n }\n\n static async getAutomations(\n limit = 50,\n offset = 0,\n ): Promise<AutomationsResponse> {\n return AutomationService.listAutomations({ limit, offset });\n }\n\n static async getAutomation(id: string): Promise<Automation> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"detail\", id)}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<Automation>({\n backend: active,\n method: \"GET\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.get<Automation>(path);\n return data;\n }\n\n static async createAutomation(spec: AutomationSpec): Promise<Automation> {\n const active = getActiveBackend();\n const { path, body } = buildCreateAutomationRequest(spec);\n\n let created: Automation;\n if (active.backend.kind === \"cloud\") {\n created = await callCloudProxy<Automation>({\n backend: active.backend,\n method: \"POST\",\n path,\n body,\n headers: await buildPinnedCloudHeaders(active),\n });\n } else {\n const { data } = await localAutomationAxios.post<Automation>(\n path,\n body,\n await buildPinnedLocalConfig(active.backend),\n );\n created = data;\n }\n\n const updatePath = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"detail\", created.id)}`;\n const updateBody: Partial<Automation> = {\n trigger: buildImportedTrigger(spec),\n enabled: false,\n };\n\n try {\n if (active.backend.kind === \"cloud\") {\n return await callCloudProxy<Automation>({\n backend: active.backend,\n method: \"PATCH\",\n path: updatePath,\n body: updateBody,\n headers: await buildPinnedCloudHeaders(active),\n });\n }\n\n const { data } = await localAutomationAxios.patch<Automation>(\n updatePath,\n updateBody,\n await buildPinnedLocalConfig(active.backend),\n );\n return data;\n } catch (updateError) {\n try {\n if (active.backend.kind === \"cloud\") {\n await callCloudProxy<unknown>({\n backend: active.backend,\n method: \"DELETE\",\n path: updatePath,\n headers: await buildPinnedCloudHeaders(active),\n });\n } else {\n await localAutomationAxios.delete(\n updatePath,\n await buildPinnedLocalConfig(active.backend),\n );\n }\n } catch (cleanupError) {\n throw new AggregateError(\n [updateError, cleanupError],\n \"Failed to disable the imported automation and clean it up.\",\n );\n }\n throw updateError;\n }\n }\n\n static async updateAutomation(\n id: string,\n body: Partial<Automation>,\n ): Promise<Automation> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"detail\", id)}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<Automation>({\n backend: active,\n method: \"PATCH\",\n path,\n body: body as Record<string, unknown>,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.patch<Automation>(path, body);\n return data;\n }\n\n static async deleteAutomation(id: string): Promise<void> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"detail\", id)}`;\n\n if (active.kind === \"cloud\") {\n await callCloudProxy<unknown>({\n backend: active,\n method: \"DELETE\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n return;\n }\n\n await localAutomationAxios.delete(path);\n }\n\n static async dispatchAutomation(id: string): Promise<AutomationRun> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"dispatch\", id)}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<AutomationRun>({\n backend: active,\n method: \"POST\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.post<AutomationRun>(path);\n return data;\n }\n\n static async listAutomationRuns(\n id: string,\n params: { limit?: number; offset?: number } = {},\n ): Promise<AutomationRunsResponse> {\n const { limit = 50, offset = 0 } = params;\n const active = getActiveBackend().backend;\n const basePath = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"runs\", id)}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<AutomationRunsResponse>({\n backend: active,\n method: \"GET\",\n path: `${basePath}?${buildPaginationQuery(limit, offset)}`,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.get<AutomationRunsResponse>(\n basePath,\n { params: { limit, offset } },\n );\n return data;\n }\n\n static async getAutomationRuns(\n id: string,\n limit = 50,\n offset = 0,\n ): Promise<AutomationRunsResponse> {\n return AutomationService.listAutomationRuns(id, { limit, offset });\n }\n\n static async toggleAutomation(\n id: string,\n enabled: boolean,\n ): Promise<Automation> {\n return AutomationService.updateAutomation(id, { enabled });\n }\n\n static async downloadTarball(id: string, name: string): Promise<void> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationIdEndpoint(\"tarball\", id)}`;\n\n let blob: Blob;\n if (active.kind === \"cloud\") {\n blob = await callCloudProxy<Blob>({\n backend: active,\n method: \"GET\",\n path,\n responseType: \"blob\",\n headers: await buildAutomationRequestHeaders(),\n });\n } else {\n const { data } = await localAutomationAxios.get<Blob>(path, {\n responseType: \"blob\",\n });\n blob = data;\n }\n\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${name}.tar`;\n a.click();\n URL.revokeObjectURL(url);\n }\n\n /**\n * Ask what this deployment supports, before a setup form renders.\n *\n * The setup endpoints answer a contract authored in `OpenHands/extensions`,\n * so their bodies are camelCase where the rest of this service is snake_case.\n */\n static async getCapabilities(): Promise<DeploymentCapabilities> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationEndpoint(\"capabilities\")}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<DeploymentCapabilities>({\n backend: active,\n method: \"GET\",\n path,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } =\n await localAutomationAxios.get<DeploymentCapabilities>(path);\n return data;\n }\n\n /**\n * Validate a draft without creating it. An invalid draft is a 200 carrying\n * field-addressed errors; only a malformed envelope is a 4xx.\n */\n static async validateDraft(\n body: SetupRequestBody,\n ): Promise<ValidateDraftResponse> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationEndpoint(\"validate\")}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<ValidateDraftResponse>({\n backend: active,\n method: \"POST\",\n path,\n body,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.post<ValidateDraftResponse>(\n path,\n body,\n );\n return data;\n }\n\n /**\n * Create from a draft a setup form derived. Unlike {@link\n * AutomationService.createAutomation}, which exists for import and has to\n * park the record on a placeholder trigger, this sends the finished record in\n * one request.\n */\n static async createAutomationDraft(\n body: SetupRequestBody,\n ): Promise<Record<string, unknown>> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${AUTOMATION_CREATE_ENDPOINT}`;\n\n if (active.kind === \"cloud\") {\n return callCloudProxy<Record<string, unknown>>({\n backend: active,\n method: \"POST\",\n path,\n body,\n headers: await buildAutomationRequestHeaders(),\n });\n }\n\n const { data } = await localAutomationAxios.post<Record<string, unknown>>(\n path,\n body,\n );\n return data;\n }\n\n static async checkHealth(): Promise<AutomationHealthResponse> {\n const active = getActiveBackend().backend;\n const path = `${AUTOMATION_BASE_PATH}${getAutomationEndpoint(\"health\")}`;\n\n try {\n if (active.kind === \"cloud\") {\n const response = await callCloudProxy<AutomationHealthResponse>({\n backend: active,\n method: \"GET\",\n path,\n // Fail fast, matching the local branch's 5s timeout below.\n timeoutSeconds: 5,\n headers: await buildAutomationRequestHeaders(),\n });\n return response;\n }\n\n const { data } = await localAutomationAxios.get<AutomationHealthResponse>(\n path,\n { timeout: 5000 },\n );\n return data;\n } catch {\n return { status: \"error\" };\n }\n }\n}\n\nexport default AutomationService;\n"],"mappings":"gaAuCA,IAAM,EAAuB,kBAkBvB,EAAuB,EAAA,QAAM,OAAO,EAE1C,eAAe,EACb,EAAuC,CAAC,EACP,CACjC,IAAM,EAAsB,MAAM,EAAA,uBAAuB,EACzD,MAAO,CACL,GAAG,EAAA,4BACH,GAAI,EACA,EAAG,EAAA,wCAAyC,CAAoB,EAChE,CAAC,EACL,GAAG,CACL,CACF,CAEA,EAAqB,aAAa,QAAQ,IAAI,KAAO,IAAW,CAC9D,IAAM,EAAiB,MAAM,EAA8B,EAO3D,GANA,OAAO,QAAQ,CAAc,EAAE,SAAS,CAAC,EAAM,KAAW,CACxD,EAAO,QAAQ,IAAI,EAAM,CAAK,CAChC,CAAC,EAIG,EAAO,QAAS,OAAO,EAU3B,IAAM,EAAU,EAAA,yBAAyB,EACzC,GAAI,CAAC,EAAS,MAAM,IAAI,EAAA,wBAExB,EAAO,QAAU,EAAQ,KAEzB,IAAM,EAAS,EAAQ,QAAQ,KAAK,EAIpC,OAHI,GACF,EAAO,QAAQ,IAAI,oBAAqB,CAAM,EAEzC,CACT,CAAC,EAED,SAAS,EAA8B,EAAiC,CAGtE,OAFI,OAAO,GAAY,UACP,EAAQ,KACjB,GAFiC,IAG1C,CAEA,SAAS,EACP,EACe,CAIf,OAHI,OAAO,GAAa,SACf,EAA8B,CAAQ,EAG7C,EAA8B,EAAS,WAAW,GAClD,EAA8B,EAAS,OAAO,CAElD,CAEA,SAAS,EAAqB,EAAe,EAAwB,CACnE,IAAM,EAAS,IAAI,gBAGnB,OAFA,EAAO,IAAI,QAAS,OAAO,CAAK,CAAC,EACjC,EAAO,IAAI,SAAU,OAAO,CAAM,CAAC,EAC5B,EAAO,SAAS,CACzB,CAEA,SAAS,EAAqB,EAAyC,CAUrE,OATI,EAAK,QAAQ,OAAS,QACjB,CACL,KAAM,QACN,OAAQ,EAAK,QAAQ,OACrB,GAAI,EAAK,QAAQ,GACjB,GAAI,EAAK,QAAQ,QAAU,CAAE,OAAQ,EAAK,QAAQ,MAAO,CAC3D,EAGK,CACL,KAAM,OACN,SAAU,EAAK,QAAQ,SACvB,SAAU,EAAK,UAAY,EAAK,QAAQ,UAAY,KACtD,CACF,CAEA,SAAS,GAAqC,CAO5C,OALE,OAAO,OAAW,KAClB,OAAO,OAAO,YAAe,WAEtB,WAAW,OAAO,WAAW,IAE/B,WAAW,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,GACxE,CAEA,SAAS,EAA6B,EAAsB,CAC1D,GAAI,CAAC,EAAK,OACR,MAAU,MAAM,8CAA8C,EAGhE,GAAM,CAAE,kBAAmB,EAAA,oBAAoB,EACzC,EAAQ,EAAK,WACf,CACE,CACE,IAAK,EAAK,WACV,GAAI,EAAK,QAAU,CAAE,IAAK,EAAK,MAAO,EACtC,GAAI,CAAC,EAAK,WAAW,SAAS,KAAK,GACjC,CAAC,EAAK,WAAW,WAAW,MAAM,GAAK,CACrC,SAAU,EAAe,YAC3B,CACJ,CACF,EACA,IAAA,GAEJ,MAAO,CACL,KAAM,GAAG,IAAuB,EAAA,sBAC9B,EAAK,SAAS,OAAS,eAAiB,cAC1C,IACA,KAAM,CACJ,KAAM,EAAK,KACX,OAAQ,EAAK,OAIb,QAAS,CACP,KAAM,QACN,OAAQ,EAAe,uBACvB,GAAI,EAA2B,CACjC,EACA,GAAI,EAAK,OAAS,CAAE,MAAO,EAAK,KAAM,EACtC,GAAI,GAAS,CAAE,OAAM,EACrB,GAAI,EAAK,SAAS,QAAU,CAC1B,QAAS,EAAK,QAAQ,IAAK,IAAY,CAAE,QAAO,EAAE,CACpD,EACA,GAAI,EAAK,SAAW,MAAQ,CAAE,QAAS,EAAK,OAAQ,CACtD,CACF,CACF,CAEA,eAAe,EAAuB,EAAkB,CACtD,IAAM,EAAS,EAAQ,OAAO,KAAK,EACnC,MAAO,CACL,QAAS,EAAQ,KACjB,QAAS,MAAM,EACb,EAAS,CAAE,oBAAqB,CAAO,EAAI,CAAC,CAC9C,CACF,CACF,CAEA,eAAe,EAAwB,EAA+B,CACpE,OAAO,EACL,EAAO,MAAQ,CAAE,WAAY,EAAO,KAAM,EAAI,CAAC,CACjD,CACF,CAEA,IAAM,EAAN,MAAM,CAAkB,CACtB,aAAa,qBACX,EAA4B,EAAA,oBAAoB,EACjC,CAEf,GADe,EAAA,iBACX,EAAO,QAAQ,OAAS,QAAS,OAErC,IAAM,EAAqB,MAAM,EAAA,qCAAqC,EACtE,MAAM,EAAqB,KACzB,GAAG,EAAqB,uBACxB,CACE,gBAAiB,IAAY,UAC7B,qBAAsB,CACxB,EACA,CAAE,QAAS,GAAK,CAClB,EACI,IAAY,WAAa,GAC3B,EAAA,qCAAqC,CAAkB,CAE3D,CAEA,aAAa,eAAwC,CACnD,IAAM,EAAS,EAAA,iBAAiB,EAC1B,EAAO,GAAG,EAAqB,cAErC,GAAI,CACF,IAAI,EACJ,GAAI,EAAO,QAAQ,OAAS,QAC1B,EAAW,MAAM,EAAA,eAA6C,CAC5D,QAAS,EAAO,QAChB,OAAQ,MACR,OACA,QAAS,MAAM,EAAwB,CAAM,EAC7C,eAAgB,CAClB,CAAC,MACI,CACL,GAAM,CAAE,QACN,MAAM,EAAqB,IAAkC,EAAM,CACjE,QAAS,GACX,CAAC,EACH,EAAW,CACb,CAEA,OAAO,EAAoC,CAAQ,CACrD,MAAQ,CACN,OAAO,IACT,CACF,CAEA,aAAa,gBACX,EAA8C,CAAC,EACjB,CAC9B,GAAM,CAAE,QAAQ,GAAI,SAAS,GAAM,EAC7B,EAAS,EAAA,iBAAiB,EAAE,QAElC,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAAoC,CACzC,QAAS,EACT,OAAQ,MACR,KAAM,GAAG,IAAuB,EAAA,sBAAsB,MAAM,EAAE,GAAG,EAAqB,EAAO,CAAM,IACnG,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,IAC1C,GAAG,IAAuB,EAAA,sBAAsB,MAAM,IACtD,CAAE,OAAQ,CAAE,QAAO,QAAO,CAAE,CAC9B,EACA,OAAO,CACT,CAEA,aAAa,eACX,EAAQ,GACR,EAAS,EACqB,CAC9B,OAAO,EAAkB,gBAAgB,CAAE,QAAO,QAAO,CAAC,CAC5D,CAEA,aAAa,cAAc,EAAiC,CAC1D,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,wBAAwB,SAAU,CAAE,IAE3E,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAA2B,CAChC,QAAS,EACT,OAAQ,MACR,OACA,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,IAAgB,CAAI,EAChE,OAAO,CACT,CAEA,aAAa,iBAAiB,EAA2C,CACvE,IAAM,EAAS,EAAA,iBAAiB,EAC1B,CAAE,OAAM,QAAS,EAA6B,CAAI,EAEpD,EACJ,GAAI,EAAO,QAAQ,OAAS,QAC1B,EAAU,MAAM,EAAA,eAA2B,CACzC,QAAS,EAAO,QAChB,OAAQ,OACR,OACA,OACA,QAAS,MAAM,EAAwB,CAAM,CAC/C,CAAC,MACI,CACL,GAAM,CAAE,QAAS,MAAM,EAAqB,KAC1C,EACA,EACA,MAAM,EAAuB,EAAO,OAAO,CAC7C,EACA,EAAU,CACZ,CAEA,IAAM,EAAa,GAAG,IAAuB,EAAA,wBAAwB,SAAU,EAAQ,EAAE,IACnF,EAAkC,CACtC,QAAS,EAAqB,CAAI,EAClC,QAAS,EACX,EAEA,GAAI,CACF,GAAI,EAAO,QAAQ,OAAS,QAC1B,OAAO,MAAM,EAAA,eAA2B,CACtC,QAAS,EAAO,QAChB,OAAQ,QACR,KAAM,EACN,KAAM,EACN,QAAS,MAAM,EAAwB,CAAM,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,MAC1C,EACA,EACA,MAAM,EAAuB,EAAO,OAAO,CAC7C,EACA,OAAO,CACT,OAAS,EAAa,CACpB,GAAI,CACE,EAAO,QAAQ,OAAS,QAC1B,MAAM,EAAA,eAAwB,CAC5B,QAAS,EAAO,QAChB,OAAQ,SACR,KAAM,EACN,QAAS,MAAM,EAAwB,CAAM,CAC/C,CAAC,EAED,MAAM,EAAqB,OACzB,EACA,MAAM,EAAuB,EAAO,OAAO,CAC7C,CAEJ,OAAS,EAAc,CACrB,MAAU,eACR,CAAC,EAAa,CAAY,EAC1B,4DACF,CACF,CACA,MAAM,CACR,CACF,CAEA,aAAa,iBACX,EACA,EACqB,CACrB,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,wBAAwB,SAAU,CAAE,IAE3E,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAA2B,CAChC,QAAS,EACT,OAAQ,QACR,OACM,OACN,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,MAAkB,EAAM,CAAI,EACxE,OAAO,CACT,CAEA,aAAa,iBAAiB,EAA2B,CACvD,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,wBAAwB,SAAU,CAAE,IAE3E,GAAI,EAAO,OAAS,QAAS,CAC3B,MAAM,EAAA,eAAwB,CAC5B,QAAS,EACT,OAAQ,SACR,OACA,QAAS,MAAM,EAA8B,CAC/C,CAAC,EACD,MACF,CAEA,MAAM,EAAqB,OAAO,CAAI,CACxC,CAEA,aAAa,mBAAmB,EAAoC,CAClE,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,wBAAwB,WAAY,CAAE,IAE7E,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAA8B,CACnC,QAAS,EACT,OAAQ,OACR,OACA,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,KAAoB,CAAI,EACpE,OAAO,CACT,CAEA,aAAa,mBACX,EACA,EAA8C,CAAC,EACd,CACjC,GAAM,CAAE,QAAQ,GAAI,SAAS,GAAM,EAC7B,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAW,GAAG,IAAuB,EAAA,wBAAwB,OAAQ,CAAE,IAE7E,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAAuC,CAC5C,QAAS,EACT,OAAQ,MACR,KAAM,GAAG,EAAS,GAAG,EAAqB,EAAO,CAAM,IACvD,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,IAC1C,EACA,CAAE,OAAQ,CAAE,QAAO,QAAO,CAAE,CAC9B,EACA,OAAO,CACT,CAEA,aAAa,kBACX,EACA,EAAQ,GACR,EAAS,EACwB,CACjC,OAAO,EAAkB,mBAAmB,EAAI,CAAE,QAAO,QAAO,CAAC,CACnE,CAEA,aAAa,iBACX,EACA,EACqB,CACrB,OAAO,EAAkB,iBAAiB,EAAI,CAAE,SAAQ,CAAC,CAC3D,CAEA,aAAa,gBAAgB,EAAY,EAA6B,CACpE,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,wBAAwB,UAAW,CAAE,IAExE,EACJ,GAAI,EAAO,OAAS,QAClB,EAAO,MAAM,EAAA,eAAqB,CAChC,QAAS,EACT,OAAQ,MACR,OACA,aAAc,OACd,QAAS,MAAM,EAA8B,CAC/C,CAAC,MACI,CACL,GAAM,CAAE,QAAS,MAAM,EAAqB,IAAU,EAAM,CAC1D,aAAc,MAChB,CAAC,EACD,EAAO,CACT,CAEA,IAAM,EAAM,IAAI,gBAAgB,CAAI,EAC9B,EAAI,SAAS,cAAc,GAAG,EACpC,EAAE,KAAO,EACT,EAAE,SAAW,GAAG,EAAK,MACrB,EAAE,MAAM,EACR,IAAI,gBAAgB,CAAG,CACzB,CAQA,aAAa,iBAAmD,CAC9D,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,sBAAsB,cAAc,IAE3E,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAAuC,CAC5C,QAAS,EACT,OAAQ,MACR,OACA,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QACN,MAAM,EAAqB,IAA4B,CAAI,EAC7D,OAAO,CACT,CAMA,aAAa,cACX,EACgC,CAChC,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,sBAAsB,UAAU,IAEvE,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAAsC,CAC3C,QAAS,EACT,OAAQ,OACR,OACA,OACA,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,KAC1C,EACA,CACF,EACA,OAAO,CACT,CAQA,aAAa,sBACX,EACkC,CAClC,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,6BAEvC,GAAI,EAAO,OAAS,QAClB,OAAO,EAAA,eAAwC,CAC7C,QAAS,EACT,OAAQ,OACR,OACA,OACA,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAGH,GAAM,CAAE,QAAS,MAAM,EAAqB,KAC1C,EACA,CACF,EACA,OAAO,CACT,CAEA,aAAa,aAAiD,CAC5D,IAAM,EAAS,EAAA,iBAAiB,EAAE,QAC5B,EAAO,GAAG,IAAuB,EAAA,sBAAsB,QAAQ,IAErE,GAAI,CACF,GAAI,EAAO,OAAS,QASlB,OAAO,MARgB,EAAA,eAAyC,CAC9D,QAAS,EACT,OAAQ,MACR,OAEA,eAAgB,EAChB,QAAS,MAAM,EAA8B,CAC/C,CAAC,EAIH,GAAM,CAAE,QAAS,MAAM,EAAqB,IAC1C,EACA,CAAE,QAAS,GAAK,CAClB,EACA,OAAO,CACT,MAAQ,CACN,MAAO,CAAE,OAAQ,OAAQ,CAC3B,CACF,CACF"}
@@ -1,5 +1,6 @@
1
1
  import { type TelemetryConsent } from "#/services/telemetry";
2
2
  import type { Automation, AutomationRun, AutomationSpec, AutomationsResponse, AutomationRunsResponse } from "#/types/automation";
3
+ import type { DeploymentCapabilities, SetupRequestBody, ValidateDraftResponse } from "#/manifests/types";
3
4
  export interface AutomationHealthResponse {
4
5
  status: "ok" | "error";
5
6
  message?: string;
@@ -24,6 +25,25 @@ declare class AutomationService {
24
25
  static getAutomationRuns(id: string, limit?: number, offset?: number): Promise<AutomationRunsResponse>;
25
26
  static toggleAutomation(id: string, enabled: boolean): Promise<Automation>;
26
27
  static downloadTarball(id: string, name: string): Promise<void>;
28
+ /**
29
+ * Ask what this deployment supports, before a setup form renders.
30
+ *
31
+ * The setup endpoints answer a contract authored in `OpenHands/extensions`,
32
+ * so their bodies are camelCase where the rest of this service is snake_case.
33
+ */
34
+ static getCapabilities(): Promise<DeploymentCapabilities>;
35
+ /**
36
+ * Validate a draft without creating it. An invalid draft is a 200 carrying
37
+ * field-addressed errors; only a malformed envelope is a 4xx.
38
+ */
39
+ static validateDraft(body: SetupRequestBody): Promise<ValidateDraftResponse>;
40
+ /**
41
+ * Create from a draft a setup form derived. Unlike {@link
42
+ * AutomationService.createAutomation}, which exists for import and has to
43
+ * park the record on a placeholder trigger, this sends the finished record in
44
+ * one request.
45
+ */
46
+ static createAutomationDraft(body: SetupRequestBody): Promise<Record<string, unknown>>;
27
47
  static checkHealth(): Promise<AutomationHealthResponse>;
28
48
  }
29
49
  export default AutomationService;
@@ -4,9 +4,11 @@ import r from "../../node_modules/axios/lib/axios.js";
4
4
  import { AGENT_CANVAS_CLIENT_HEADERS as i, OPENHANDS_TELEMETRY_DISTINCT_ID_HEADER as a } from "../client-source.js";
5
5
  import { clearPendingLocalTelemetryRevocation as o, getTelemetryConsent as s, getTelemetryDistinctId as c, getTelemetryDistinctIdForConsentSync as l } from "../../services/telemetry.js";
6
6
  import { callCloudProxy as u } from "../cloud/proxy.js";
7
+ import { getAutomationEndpoint as d, getAutomationIdEndpoint as f, getImportExportSpec as p } from "../../manifests/automation-interface.js";
8
+ import { AUTOMATION_CREATE_ENDPOINT as m } from "../../manifests/automation-setup.js";
7
9
  //#region src/api/automation-service/automation-service.api.ts
8
- var d = "/api/automation", f = r.create();
9
- async function p(e = {}) {
10
+ var h = "/api/automation", g = r.create();
11
+ async function _(e = {}) {
10
12
  let t = await c();
11
13
  return {
12
14
  ...i,
@@ -14,8 +16,8 @@ async function p(e = {}) {
14
16
  ...e
15
17
  };
16
18
  }
17
- f.interceptors.request.use(async (e) => {
18
- let r = await p();
19
+ g.interceptors.request.use(async (e) => {
20
+ let r = await _();
19
21
  if (Object.entries(r).forEach(([t, n]) => {
20
22
  e.headers.set(t, n);
21
23
  }), e.baseURL) return e;
@@ -25,17 +27,17 @@ f.interceptors.request.use(async (e) => {
25
27
  let a = i.apiKey?.trim();
26
28
  return a && e.headers.set("X-Session-API-Key", a), e;
27
29
  });
28
- function m(e) {
30
+ function v(e) {
29
31
  return typeof e == "string" && e.trim() || null;
30
32
  }
31
- function h(e) {
32
- return typeof e == "string" ? m(e) : m(e.sdk_version) ?? m(e.version);
33
+ function y(e) {
34
+ return typeof e == "string" ? v(e) : v(e.sdk_version) ?? v(e.version);
33
35
  }
34
- function g(e, t) {
36
+ function b(e, t) {
35
37
  let n = new URLSearchParams();
36
38
  return n.set("limit", String(e)), n.set("offset", String(t)), n.toString();
37
39
  }
38
- function _(e) {
40
+ function x(e) {
39
41
  return e.trigger.type === "event" ? {
40
42
  type: "event",
41
43
  source: e.trigger.source,
@@ -47,68 +49,68 @@ function _(e) {
47
49
  timezone: e.timezone ?? e.trigger.timezone ?? "UTC"
48
50
  };
49
51
  }
50
- function v() {
52
+ function S() {
51
53
  return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? `pending.${crypto.randomUUID()}` : `pending.${Date.now()}.${Math.random().toString(36).slice(2, 10)}`;
52
54
  }
53
- function y(e) {
55
+ function C(e) {
54
56
  if (!e.prompt) throw Error("An automation prompt is required for import.");
55
- let t = e.repository ? [{
57
+ let { importDefaults: t } = p(), n = e.repository ? [{
56
58
  url: e.repository,
57
59
  ...e.branch && { ref: e.branch },
58
- ...!e.repository.includes("://") && !e.repository.startsWith("git@") && { provider: "github" }
60
+ ...!e.repository.includes("://") && !e.repository.startsWith("git@") && { provider: t.repoProvider }
59
61
  }] : void 0;
60
62
  return {
61
- path: `${d}/v1/preset/${e.plugins?.length ? "plugin" : "prompt"}`,
63
+ path: `${h}${d(e.plugins?.length ? "createPlugin" : "createPrompt")}`,
62
64
  body: {
63
65
  name: e.name,
64
66
  prompt: e.prompt,
65
67
  trigger: {
66
68
  type: "event",
67
- source: "agent-canvas-import",
68
- on: v()
69
+ source: t.placeholderEventSource,
70
+ on: S()
69
71
  },
70
72
  ...e.model && { model: e.model },
71
- ...t && { repos: t },
73
+ ...n && { repos: n },
72
74
  ...e.plugins?.length && { plugins: e.plugins.map((e) => ({ source: e })) },
73
75
  ...e.timeout != null && { timeout: e.timeout }
74
76
  }
75
77
  };
76
78
  }
77
- async function b(e) {
79
+ async function w(e) {
78
80
  let t = e.apiKey.trim();
79
81
  return {
80
82
  baseURL: e.host,
81
- headers: await p(t ? { "X-Session-API-Key": t } : {})
83
+ headers: await _(t ? { "X-Session-API-Key": t } : {})
82
84
  };
83
85
  }
84
- async function x(e) {
85
- return p(e.orgId ? { "X-Org-Id": e.orgId } : {});
86
+ async function T(e) {
87
+ return _(e.orgId ? { "X-Org-Id": e.orgId } : {});
86
88
  }
87
- var S = class t {
89
+ var E = class t {
88
90
  static async syncTelemetryConsent(t = s()) {
89
91
  if (e().backend.kind !== "local") return;
90
92
  let n = await l();
91
- await f.post(`${d}/v1/telemetry/consent`, {
93
+ await g.post(`${h}/v1/telemetry/consent`, {
92
94
  consent_granted: t === "granted",
93
95
  frontend_distinct_id: n
94
96
  }, { timeout: 5e3 }), t !== "granted" && n && o(n);
95
97
  }
96
98
  static async getSdkVersion() {
97
- let t = e(), n = `${d}/sdk-version`;
99
+ let t = e(), n = `${h}/sdk-version`;
98
100
  try {
99
101
  let e;
100
102
  if (t.backend.kind === "cloud") e = await u({
101
103
  backend: t.backend,
102
104
  method: "GET",
103
105
  path: n,
104
- headers: await x(t),
106
+ headers: await T(t),
105
107
  timeoutSeconds: 5
106
108
  });
107
109
  else {
108
- let { data: t } = await f.get(n, { timeout: 5e3 });
110
+ let { data: t } = await g.get(n, { timeout: 5e3 });
109
111
  e = t;
110
112
  }
111
- return h(e);
113
+ return y(e);
112
114
  } catch {
113
115
  return null;
114
116
  }
@@ -118,10 +120,10 @@ var S = class t {
118
120
  if (i.kind === "cloud") return u({
119
121
  backend: i,
120
122
  method: "GET",
121
- path: `${d}/v1?${g(n, r)}`,
122
- headers: await p()
123
+ path: `${h}${d("list")}?${b(n, r)}`,
124
+ headers: await _()
123
125
  });
124
- let { data: a } = await f.get(`${d}/v1`, { params: {
126
+ let { data: a } = await g.get(`${h}${d("list")}`, { params: {
125
127
  limit: n,
126
128
  offset: r
127
129
  } });
@@ -134,31 +136,31 @@ var S = class t {
134
136
  });
135
137
  }
136
138
  static async getAutomation(t) {
137
- let n = e().backend, r = `${d}/v1/${encodeURIComponent(t)}`;
139
+ let n = e().backend, r = `${h}${f("detail", t)}`;
138
140
  if (n.kind === "cloud") return u({
139
141
  backend: n,
140
142
  method: "GET",
141
143
  path: r,
142
- headers: await p()
144
+ headers: await _()
143
145
  });
144
- let { data: i } = await f.get(r);
146
+ let { data: i } = await g.get(r);
145
147
  return i;
146
148
  }
147
149
  static async createAutomation(t) {
148
- let n = e(), { path: r, body: i } = y(t), a;
150
+ let n = e(), { path: r, body: i } = C(t), a;
149
151
  if (n.backend.kind === "cloud") a = await u({
150
152
  backend: n.backend,
151
153
  method: "POST",
152
154
  path: r,
153
155
  body: i,
154
- headers: await x(n)
156
+ headers: await T(n)
155
157
  });
156
158
  else {
157
- let { data: e } = await f.post(r, i, await b(n.backend));
159
+ let { data: e } = await g.post(r, i, await w(n.backend));
158
160
  a = e;
159
161
  }
160
- let o = `${d}/v1/${encodeURIComponent(a.id)}`, s = {
161
- trigger: _(t),
162
+ let o = `${h}${f("detail", a.id)}`, s = {
163
+ trigger: x(t),
162
164
  enabled: !1
163
165
  };
164
166
  try {
@@ -167,9 +169,9 @@ var S = class t {
167
169
  method: "PATCH",
168
170
  path: o,
169
171
  body: s,
170
- headers: await x(n)
172
+ headers: await T(n)
171
173
  });
172
- let { data: e } = await f.patch(o, s, await b(n.backend));
174
+ let { data: e } = await g.patch(o, s, await w(n.backend));
173
175
  return e;
174
176
  } catch (e) {
175
177
  try {
@@ -177,8 +179,8 @@ var S = class t {
177
179
  backend: n.backend,
178
180
  method: "DELETE",
179
181
  path: o,
180
- headers: await x(n)
181
- }) : await f.delete(o, await b(n.backend));
182
+ headers: await T(n)
183
+ }) : await g.delete(o, await w(n.backend));
182
184
  } catch (t) {
183
185
  throw AggregateError([e, t], "Failed to disable the imported automation and clean it up.");
184
186
  }
@@ -186,50 +188,50 @@ var S = class t {
186
188
  }
187
189
  }
188
190
  static async updateAutomation(t, n) {
189
- let r = e().backend, i = `${d}/v1/${encodeURIComponent(t)}`;
191
+ let r = e().backend, i = `${h}${f("detail", t)}`;
190
192
  if (r.kind === "cloud") return u({
191
193
  backend: r,
192
194
  method: "PATCH",
193
195
  path: i,
194
196
  body: n,
195
- headers: await p()
197
+ headers: await _()
196
198
  });
197
- let { data: a } = await f.patch(i, n);
199
+ let { data: a } = await g.patch(i, n);
198
200
  return a;
199
201
  }
200
202
  static async deleteAutomation(t) {
201
- let n = e().backend, r = `${d}/v1/${encodeURIComponent(t)}`;
203
+ let n = e().backend, r = `${h}${f("detail", t)}`;
202
204
  if (n.kind === "cloud") {
203
205
  await u({
204
206
  backend: n,
205
207
  method: "DELETE",
206
208
  path: r,
207
- headers: await p()
209
+ headers: await _()
208
210
  });
209
211
  return;
210
212
  }
211
- await f.delete(r);
213
+ await g.delete(r);
212
214
  }
213
215
  static async dispatchAutomation(t) {
214
- let n = e().backend, r = `${d}/v1/${encodeURIComponent(t)}/dispatch`;
216
+ let n = e().backend, r = `${h}${f("dispatch", t)}`;
215
217
  if (n.kind === "cloud") return u({
216
218
  backend: n,
217
219
  method: "POST",
218
220
  path: r,
219
- headers: await p()
221
+ headers: await _()
220
222
  });
221
- let { data: i } = await f.post(r);
223
+ let { data: i } = await g.post(r);
222
224
  return i;
223
225
  }
224
226
  static async listAutomationRuns(t, n = {}) {
225
- let { limit: r = 50, offset: i = 0 } = n, a = e().backend, o = `${d}/v1/${encodeURIComponent(t)}/runs`;
227
+ let { limit: r = 50, offset: i = 0 } = n, a = e().backend, o = `${h}${f("runs", t)}`;
226
228
  if (a.kind === "cloud") return u({
227
229
  backend: a,
228
230
  method: "GET",
229
- path: `${o}?${g(r, i)}`,
230
- headers: await p()
231
+ path: `${o}?${b(r, i)}`,
232
+ headers: await _()
231
233
  });
232
- let { data: s } = await f.get(o, { params: {
234
+ let { data: s } = await g.get(o, { params: {
233
235
  limit: r,
234
236
  offset: i
235
237
  } });
@@ -245,32 +247,67 @@ var S = class t {
245
247
  return t.updateAutomation(e, { enabled: n });
246
248
  }
247
249
  static async downloadTarball(t, n) {
248
- let r = e().backend, i = `${d}/v1/${encodeURIComponent(t)}/tarball`, a;
250
+ let r = e().backend, i = `${h}${f("tarball", t)}`, a;
249
251
  if (r.kind === "cloud") a = await u({
250
252
  backend: r,
251
253
  method: "GET",
252
254
  path: i,
253
255
  responseType: "blob",
254
- headers: await p()
256
+ headers: await _()
255
257
  });
256
258
  else {
257
- let { data: e } = await f.get(i, { responseType: "blob" });
259
+ let { data: e } = await g.get(i, { responseType: "blob" });
258
260
  a = e;
259
261
  }
260
262
  let o = URL.createObjectURL(a), s = document.createElement("a");
261
263
  s.href = o, s.download = `${n}.tar`, s.click(), URL.revokeObjectURL(o);
262
264
  }
265
+ static async getCapabilities() {
266
+ let t = e().backend, n = `${h}${d("capabilities")}`;
267
+ if (t.kind === "cloud") return u({
268
+ backend: t,
269
+ method: "GET",
270
+ path: n,
271
+ headers: await _()
272
+ });
273
+ let { data: r } = await g.get(n);
274
+ return r;
275
+ }
276
+ static async validateDraft(t) {
277
+ let n = e().backend, r = `${h}${d("validate")}`;
278
+ if (n.kind === "cloud") return u({
279
+ backend: n,
280
+ method: "POST",
281
+ path: r,
282
+ body: t,
283
+ headers: await _()
284
+ });
285
+ let { data: i } = await g.post(r, t);
286
+ return i;
287
+ }
288
+ static async createAutomationDraft(t) {
289
+ let n = e().backend, r = `${h}${m}`;
290
+ if (n.kind === "cloud") return u({
291
+ backend: n,
292
+ method: "POST",
293
+ path: r,
294
+ body: t,
295
+ headers: await _()
296
+ });
297
+ let { data: i } = await g.post(r, t);
298
+ return i;
299
+ }
263
300
  static async checkHealth() {
264
- let t = e().backend, n = `${d}/health`;
301
+ let t = e().backend, n = `${h}${d("health")}`;
265
302
  try {
266
303
  if (t.kind === "cloud") return await u({
267
304
  backend: t,
268
305
  method: "GET",
269
306
  path: n,
270
307
  timeoutSeconds: 5,
271
- headers: await p()
308
+ headers: await _()
272
309
  });
273
- let { data: e } = await f.get(n, { timeout: 5e3 });
310
+ let { data: e } = await g.get(n, { timeout: 5e3 });
274
311
  return e;
275
312
  } catch {
276
313
  return { status: "error" };
@@ -278,6 +315,6 @@ var S = class t {
278
315
  }
279
316
  };
280
317
  //#endregion
281
- export { S as default };
318
+ export { E as default };
282
319
 
283
320
  //# sourceMappingURL=automation-service.api.js.map