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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (409) hide show
  1. package/README.md +17 -6
  2. package/bin/agent-canvas.mjs +22 -2
  3. package/build/assets/{QueryClientProvider-B7kl84Kj.js → QueryClientProvider-CkGuhXg-.js} +1 -1
  4. package/build/assets/{Trans-1j65oy9O.js → Trans-Cvm_-SMi.js} +1 -1
  5. package/build/assets/acp-providers-CbiRekh9.js +1 -0
  6. package/build/assets/{acp-route-guard-CQTmeJwM.js → acp-route-guard-B2yoBZ_4.js} +1 -1
  7. package/build/assets/{active-backend-context-TVbjnvmP.js → active-backend-context-cCM1vYYZ.js} +1 -1
  8. package/build/assets/add-backend-modal-DIUQzMPa.js +1 -0
  9. package/build/assets/agent-server-client-options-Bc5ZorQZ.js +1 -0
  10. package/build/assets/agent-server-compatibility-BlkUsrX2.js +1 -0
  11. package/build/assets/agent-server-conversation-service.api-DFvqqEDo.js +5 -0
  12. package/build/assets/{agent-settings-B247S9G3.js → agent-settings-CnGSCmK8.js} +1 -1
  13. package/build/assets/{alert-banner-BWoqueRw.js → alert-banner-DtzAX654.js} +1 -1
  14. package/build/assets/{analytics-consent-form-modal-C7sXfxRh.js → analytics-consent-form-modal-CHZ3I37v.js} +1 -1
  15. package/build/assets/api-key-entry-screen-B2gynaCp.js +1 -0
  16. package/build/assets/{app-settings-BVeSaty9.js → app-settings-Db9ITeJH.js} +1 -1
  17. package/build/assets/{automation-detail-g5-RZ0da.js → automation-detail-Di7EOIZD.js} +1 -1
  18. package/build/assets/{automations-list-DHoq_0MM.js → automations-list-IsIWdDiw.js} +1 -1
  19. package/build/assets/backend-form-modal-Dnk33xA_.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-nAfiUWvM.js → backend-synced-settings-badge-Dc6c7GT4.js} +1 -1
  21. package/build/assets/{base-modal-CQRvRHu1.js → base-modal-_dYTw1ri.js} +1 -1
  22. package/build/assets/{brand-button-C2nEKopC.js → brand-button-Br7f0kZJ.js} +1 -1
  23. package/build/assets/browser-D810xUYt.js +5 -0
  24. package/build/assets/browser-store-Couc4S5D.js +1 -0
  25. package/build/assets/browser-tab-B-aIqXRl.js +1 -0
  26. package/build/assets/{checkmark-BJJrZUF8.js → checkmark-DL7acQA7.js} +1 -1
  27. package/build/assets/{chevron-left-small-CSh-sE9L.js → chevron-left-small-CVWf8TI6.js} +1 -1
  28. package/build/assets/{circle-plus-check-toggle-qs8Va1cC.js → circle-plus-check-toggle-P7ZZToV4.js} +1 -1
  29. package/build/assets/{clock-ZR4Kn-_Y.js → clock-BRjCgHTc.js} +1 -1
  30. package/build/assets/{close-BdmyeRqS.js → close-B5LROHR3.js} +1 -1
  31. package/build/assets/{combobox-caret-B53O9Hsq.js → combobox-caret-to1O8irE.js} +1 -1
  32. package/build/assets/{condenser-settings-A35V3yng.js → condenser-settings-wnEKhBof.js} +1 -1
  33. package/build/assets/{confirmation-modal-C9-La0h3.js → confirmation-modal-Dau3w_sa.js} +1 -1
  34. package/build/assets/{context-menu-list-item-Buu9nc0q.js → context-menu-list-item-CWNFpuiC.js} +1 -1
  35. package/build/assets/conversation-HlncOV7n.js +19 -0
  36. package/build/assets/conversation-MtnkpqA9.js +1 -0
  37. package/build/assets/conversation-panel-DxnM6tRe.js +1 -0
  38. package/build/assets/{conversation-service.api-C8pYCyV6.js → conversation-service.api-nb5W1PqR.js} +1 -1
  39. package/build/assets/{conversation-tab-empty-state-D8dNvo-V.js → conversation-tab-empty-state-DyssnnWa.js} +1 -1
  40. package/build/assets/conversation-websocket-context-C8_PkGLi.js +3 -0
  41. package/build/assets/{copy-C7Ti2d8C.js → copy-DYgmUdIw.js} +1 -1
  42. package/build/assets/{custom-toast-handlers-BOc3qeQ7.js → custom-toast-handlers-C-SZFmto.js} +1 -1
  43. package/build/assets/declaration-BNMqORFE.js +1 -0
  44. package/build/assets/{device-verify-CMusn8nX.js → device-verify-DqDlphsG.js} +1 -1
  45. package/build/assets/{dist-DZHSA2e6.js → dist-C6t0EXL7.js} +1 -1
  46. package/build/assets/{edit-automation-modal-Dnjxbjn7.js → edit-automation-modal-BGzR3nfZ.js} +1 -1
  47. package/build/assets/{ellipsis-button-ugUATsNo.js → ellipsis-button-ZyLMPURn.js} +1 -1
  48. package/build/assets/{entry.client-D9uR9Blz.js → entry.client-1VMHpktY.js} +2 -2
  49. package/build/assets/{enum-filter-dropdown-1vpOGySB.js → enum-filter-dropdown-CEgCdu4A.js} +1 -1
  50. package/build/assets/{environment-switch-overlay-CTCTQikP.js → environment-switch-overlay-XL8yCGP6.js} +1 -1
  51. package/build/assets/{extensions-hub-BSUseHVF.js → extensions-hub-C651jsVh.js} +1 -1
  52. package/build/assets/{extensions-navigation-CT1kc1u_.js → extensions-navigation-BYR8Giqq.js} +1 -1
  53. package/build/assets/files-tab-BhnLgimi.js +1 -0
  54. package/build/assets/{folder-0WSMImNX.js → folder-ZZJVGgd7.js} +1 -1
  55. package/build/assets/git-control-bar-branch-button-M34A5_vX.js +27 -0
  56. package/build/assets/{git-provider-icon-DYE9n7fs.js → git-provider-icon-D5dCNy-k.js} +1 -1
  57. package/build/assets/home-CYQv7yc_.js +1 -0
  58. package/build/assets/{i18n-DjAGhTis.js → i18n-CTohRuoO.js} +1 -1
  59. package/build/assets/install-server-modal-f31_CLrW.js +1 -0
  60. package/build/assets/{launch-hZ0ifhcV.js → launch-DHEUYn2A.js} +1 -1
  61. package/build/assets/{lesson-plan-DRYG5SLI.js → lesson-plan-dH5Bj0pN.js} +1 -1
  62. package/build/assets/{link-external-Df8J52xI.js → link-external-D2POYx4c.js} +1 -1
  63. package/build/assets/{llm-client-ChQzg4wX.js → llm-client-DaH1TuyR.js} +1 -1
  64. package/build/assets/llm-settings-Bql-vydt.js +1 -0
  65. package/build/assets/llm-settings-C_tal6Ds.js +1 -0
  66. package/build/assets/{loading-spinner-C04FGh14.js → loading-spinner-BPtYORNK.js} +1 -1
  67. package/build/assets/{manage-backends-modal-rYeyGx7j.js → manage-backends-modal-l7RkKfwX.js} +1 -1
  68. package/build/assets/{manage-workspaces-modal-C5EuW8m1.js → manage-workspaces-modal-DhKF_8z3.js} +1 -1
  69. package/build/assets/manifest-9fee01b9.js +1 -0
  70. package/build/assets/{markdown-renderer-CEX4Becj.js → markdown-renderer-DMzf2i4x.js} +1 -1
  71. package/build/assets/mcp-D2onbwVk.js +9 -0
  72. package/build/assets/{messages-T2ewVkbp.js → messages-BMzyOW2V.js} +1 -1
  73. package/build/assets/{modal-backdrop-DTYGVmOR.js → modal-backdrop-BAbgYsqB.js} +1 -1
  74. package/build/assets/{modal-body-YElmM1dV.js → modal-body-BI6Ru2Qr.js} +1 -1
  75. package/build/assets/{modal-close-button-C_GpQt9F.js → modal-close-button-t1Gh3qmL.js} +1 -1
  76. package/build/assets/{model-selector-DeMmw-Xa.js → model-selector-SM9IUz-q.js} +1 -1
  77. package/build/assets/{mutation-Cz7N4XAo.js → mutation-D0OogFCz.js} +1 -1
  78. package/build/assets/{navigation-context-DeIPtGPp.js → navigation-context-D0YWpT8d.js} +1 -1
  79. package/build/assets/{navigation-link-C9JD4PYD.js → navigation-link-Cn7KP3c5.js} +1 -1
  80. package/build/assets/{openhands-logo-CI5Fhn1W.js → openhands-logo-CnrF6LKb.js} +1 -1
  81. package/build/assets/{option-service.api-DsI1UW7N.js → option-service.api-KvY_mZMY.js} +1 -1
  82. package/build/assets/{organization-service.api-COwMPFg5.js → organization-service.api-DzYTHTYC.js} +1 -1
  83. package/build/assets/{path-utils-CqJboYxo.js → path-utils-YohAYyMv.js} +1 -1
  84. package/build/assets/{plan-components-DEjMuDDG.js → plan-components-atxXCF0R.js} +1 -1
  85. package/build/assets/{planner-tab-BrntFmb1.js → planner-tab-CFc-hV07.js} +1 -1
  86. package/build/assets/{profiles-client-BGkKEV9j.js → profiles-client-D6IkTJof.js} +1 -1
  87. package/build/assets/{providers-DXvCAN_u.js → providers-Bx6EfrzZ.js} +1 -1
  88. package/build/assets/{proxy-CurRmrqf.js → proxy-CxydCnis.js} +1 -1
  89. package/build/assets/{query-client-config-Ba7qAAoO.js → query-client-config-B7u9asM0.js} +1 -1
  90. package/build/assets/{recommended-automations-launcher-BI9NhG8Y.js → recommended-automations-launcher-sgvfU62c.js} +3 -3
  91. package/build/assets/root-BXWU99D-.js +2 -0
  92. package/build/assets/{root-layout-BLjAEgle.js → root-layout-DVepR4To.js} +2 -2
  93. package/build/assets/sdk-section-page-DOIKvwSL.js +1 -0
  94. package/build/assets/{sdk-settings-schema-QBYH-ONX.js → sdk-settings-schema-DsUf9wu1.js} +1 -1
  95. package/build/assets/{search-Cq_cFrDt.js → search-27Owlc3A.js} +1 -1
  96. package/build/assets/{secrets-service-Bwd5DeUs.js → secrets-service-BsnKFc2x.js} +1 -1
  97. package/build/assets/secrets-settings-Bz_UohPJ.js +1 -0
  98. package/build/assets/{server-client-C3mC8Hl3.js → server-client-DyAQ3NZ_.js} +1 -1
  99. package/build/assets/{settings-D7E2U5tK.js → settings-BYkVX7vW.js} +1 -1
  100. package/build/assets/{settings-client-CwjfwoiB.js → settings-client-C73C7IgV.js} +1 -1
  101. package/build/assets/{settings-dropdown-input-VwAXNrOb.js → settings-dropdown-input-BJYvGdg-.js} +1 -1
  102. package/build/assets/{settings-gear-BJwWR1ej.js → settings-gear-C77PgE_O.js} +1 -1
  103. package/build/assets/{settings-index-J-3BNR0W.js → settings-index-Dz0BmdJD.js} +1 -1
  104. package/build/assets/{settings-input-DBywAnA7.js → settings-input-Bn7F5C75.js} +1 -1
  105. package/build/assets/{settings-list-classes-BOS092DR.js → settings-list-classes-Bf80tWtc.js} +1 -1
  106. package/build/assets/{settings-modal-B8vgWDTe.js → settings-modal-Brzgh5Yw.js} +1 -1
  107. package/build/assets/{settings-section-header-context-32x6WTyL.js → settings-section-header-context-BgZe5YkE.js} +1 -1
  108. package/build/assets/{settings-service.api-FvJGK45W.js → settings-service.api-CZ3uWx4v.js} +1 -1
  109. package/build/assets/{settings-switch-DTKmHC8F.js → settings-switch-BeIKrWms.js} +1 -1
  110. package/build/assets/{shared-conversation-a0QV8o99.js → shared-conversation-DChOdb0t.js} +1 -1
  111. package/build/assets/{sidebar-mobile-menu-toggle-DTUNI1WQ.js → sidebar-mobile-menu-toggle-BWuf4PRH.js} +1 -1
  112. package/build/assets/{sidebar-nav-link-CnWoZcwc.js → sidebar-nav-link-BGjiJq-4.js} +1 -1
  113. package/build/assets/{skill-card-pill-row-tZ599jli.js → skill-card-pill-row-DF1axQCG.js} +1 -1
  114. package/build/assets/{skills-ZyAO5dyK.js → skills-ChIKZPK4.js} +1 -1
  115. package/build/assets/{skills-plugins-BSRz041I.js → skills-plugins-CcI_19lM.js} +1 -1
  116. package/build/assets/{skills-settings-DOnMn9q1.js → skills-settings-DlA5hlXw.js} +1 -1
  117. package/build/assets/{status-CsatcFbK.js → status-hp6M6E7E.js} +1 -1
  118. package/build/assets/{styled-tooltip-CS3mB_1X.js → styled-tooltip-CBzrri6o.js} +1 -1
  119. package/build/assets/{switch-skeleton-C-CfhYYV.js → switch-skeleton-DnC9wLp7.js} +1 -1
  120. package/build/assets/{task-list-tab-Day9nhRT.js → task-list-tab-DUJn1sgz.js} +1 -1
  121. package/build/assets/{terminal-ro4SNjUU.js → terminal-CRf9S0Z2.js} +1 -1
  122. package/build/assets/{terminal-LNa-iU5c.js → terminal-RmuaSdhJ.js} +1 -1
  123. package/build/assets/{toggle-switch-k-IZCDbt.js → toggle-switch-Pvyp2RAN.js} +1 -1
  124. package/build/assets/{typography-vVUMoNUg.js → typography-gpuWmrQO.js} +1 -1
  125. package/build/assets/{u-check-circle-DplbarS5.js → u-check-circle-IUIfACQQ.js} +1 -1
  126. package/build/assets/{u-check-circle-half-yDuiSZHC.js → u-check-circle-half-C1YxB6py.js} +1 -1
  127. package/build/assets/{u-circuit-C9tYkpeK.js → u-circuit-BmVikJHu.js} +1 -1
  128. package/build/assets/{u-edit-KAUlufD8.js → u-edit-CFvXHqZk.js} +1 -1
  129. package/build/assets/use-active-conversation-Db3IWSPK.js +1 -0
  130. package/build/assets/{use-agent-settings-schema-Bvp5UzV8.js → use-agent-settings-schema-33Un7UF2.js} +1 -1
  131. package/build/assets/{use-agent-state-DE5dlEXJ.js → use-agent-state-Bn8vS5sY.js} +1 -1
  132. package/build/assets/{use-cloud-current-user-id-DWVar4st.js → use-cloud-current-user-id-CvkXFnTT.js} +1 -1
  133. package/build/assets/use-config-Co1O8-Ey.js +1 -0
  134. package/build/assets/{use-create-conversation-DW7AGgLA.js → use-create-conversation-CKS3EAHu.js} +1 -1
  135. package/build/assets/{use-event-store-CQZCcVz-.js → use-event-store-BT_gV3ut.js} +1 -1
  136. package/build/assets/use-get-secrets-DuhdIA59.js +1 -0
  137. package/build/assets/{use-handle-plan-click-DpgEQDAV.js → use-handle-plan-click-C9zJpK8A.js} +1 -1
  138. package/build/assets/use-is-authed-BggE5wPj.js +1 -0
  139. package/build/assets/{use-is-creating-conversation-DhDeeWfA.js → use-is-creating-conversation-BZ5hB_Bg.js} +1 -1
  140. package/build/assets/{use-launch-skill-in-chat-DVGPFrbI.js → use-launch-skill-in-chat-fNN_xGZG.js} +1 -1
  141. package/build/assets/{use-llm-profiles-D3-KXwQ0.js → use-llm-profiles-DDOol3gK.js} +1 -1
  142. package/build/assets/use-runtime-is-ready-CQCE3xZC.js +1 -0
  143. package/build/assets/{use-save-settings-CEEKSTWG.js → use-save-settings-VUrj_QNG.js} +1 -1
  144. package/build/assets/{use-settings-DQ7Oo1Hj.js → use-settings-DQIZmIov.js} +1 -1
  145. package/build/assets/{use-settings-nav-items-YmrXrjn9.js → use-settings-nav-items-1ZvovKSr.js} +1 -1
  146. package/build/assets/use-skills-DAMLFjKU.js +1 -0
  147. package/build/assets/{use-task-list-Bs90uF2N.js → use-task-list-CLJbuJgM.js} +1 -1
  148. package/build/assets/use-unified-vscode-url-sZt29HrC.js +1 -0
  149. package/build/assets/use-user-conversation-DfgEB6RW.js +1 -0
  150. package/build/assets/{useMutation-B4OUESdw.js → useMutation-DqrumCWD.js} +1 -1
  151. package/build/assets/{useTranslation-CpIcQBq6.js → useTranslation-DCOdSSMl.js} +1 -1
  152. package/build/assets/{utils-D-HX7JCe.js → utils-i18rdUj2.js} +1 -1
  153. package/build/assets/v4-CNn21NXa.js +1 -0
  154. package/build/assets/{vendor~browser-Dr71AdrG.js → vendor~browser-BNjNhjFU.js} +1 -1
  155. package/build/assets/{vendor~browser-tab-BiVxfjJo.js → vendor~browser-tab-BgwV1mxF.js} +1 -1
  156. package/build/assets/{vendor~conversation-panel~conversation-BlCIz9XQ.js → vendor~conversation-panel~conversation-a9SyrrhV.js} +1 -1
  157. package/build/assets/{vendor~files-tab-DtLR-QD9.js → vendor~files-tab-BGKayPiK.js} +1 -1
  158. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ds9quNZ9.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-smY2r837.js} +1 -1
  159. package/build/assets/{vendor~home~mcp~automations-list-C5PoHCy6.js → vendor~home~mcp~automations-list-Ccy2I0KU.js} +1 -1
  160. package/build/assets/{vendor~home~mcp~automations-list-BUBGGGYz.js → vendor~home~mcp~automations-list-DoPfwaXj.js} +1 -1
  161. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CGlZoBKa.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DbfELDJu.js} +2 -2
  162. package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-DE11mPxp.js → vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-Z3nsiNNq.js} +1 -1
  163. package/build/assets/{vendor~launch-Dg--Ssk6.js → vendor~launch-vdeRTWFu.js} +1 -1
  164. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-DrXgiSCq.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DW31UyBp.js} +1 -1
  165. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-8b8V5bfO.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-BkQGKpye.js} +1 -1
  166. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-Dy7L6fMG.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-DzIXV3Ui.js} +1 -1
  167. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D40EXhZx.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-Bbs7UJ5U.js} +2 -2
  168. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-CHrEOFl6.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~dp08i1qy-DTwbEEcX.js} +1 -1
  169. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BP1SKG0F.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-d2oallMa.js} +1 -1
  170. package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~kyz9p27j-CyUbhpbm.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~f2l2lr17-CDXvdvb2.js} +1 -1
  171. package/build/assets/{verification-settings-BtlTiHP8.js → verification-settings-CsbvQcYS.js} +1 -1
  172. package/build/assets/{vscode-tab-C0ShhiSU.js → vscode-tab-Zb-QbTuV.js} +1 -1
  173. package/build/assets/{waiting-for-runtime-message-DWPl_Yby.js → waiting-for-runtime-message-CntjExbU.js} +1 -1
  174. package/build/assets/{x-mark-CWI0f9yI.js → x-mark-CrpjscNc.js} +1 -1
  175. package/build/index.html +4 -4
  176. package/build/locales/ar/openhands.json +7 -0
  177. package/build/locales/ca/openhands.json +7 -0
  178. package/build/locales/de/openhands.json +7 -0
  179. package/build/locales/en/openhands.json +7 -0
  180. package/build/locales/es/openhands.json +7 -0
  181. package/build/locales/fr/openhands.json +7 -0
  182. package/build/locales/it/openhands.json +7 -0
  183. package/build/locales/ja/openhands.json +7 -0
  184. package/build/locales/ko-KR/openhands.json +7 -0
  185. package/build/locales/no/openhands.json +7 -0
  186. package/build/locales/pt/openhands.json +7 -0
  187. package/build/locales/tr/openhands.json +7 -0
  188. package/build/locales/uk/openhands.json +7 -0
  189. package/build/locales/zh-CN/openhands.json +7 -0
  190. package/build/locales/zh-TW/openhands.json +7 -0
  191. package/config/defaults.json +0 -4
  192. package/dist/api/agent-server-adapter.cjs +1 -1
  193. package/dist/api/agent-server-adapter.cjs.map +1 -1
  194. package/dist/api/agent-server-adapter.js +2 -1
  195. package/dist/api/agent-server-adapter.js.map +1 -1
  196. package/dist/api/agent-server-compatibility.cjs +1 -1
  197. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  198. package/dist/api/agent-server-compatibility.d.ts +16 -0
  199. package/dist/api/agent-server-compatibility.js +31 -20
  200. package/dist/api/agent-server-compatibility.js.map +1 -1
  201. package/dist/api/agent-server-config.cjs +1 -1
  202. package/dist/api/agent-server-config.cjs.map +1 -1
  203. package/dist/api/agent-server-config.d.ts +45 -0
  204. package/dist/api/agent-server-config.js +49 -21
  205. package/dist/api/agent-server-config.js.map +1 -1
  206. package/dist/api/backend-registry/storage.cjs +1 -1
  207. package/dist/api/backend-registry/storage.cjs.map +1 -1
  208. package/dist/api/backend-registry/storage.js +34 -32
  209. package/dist/api/backend-registry/storage.js.map +1 -1
  210. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  211. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  212. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +5 -4
  213. package/dist/api/conversation-service/agent-server-conversation-service.api.js +70 -76
  214. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  215. package/dist/api/skills-service.cjs +1 -1
  216. package/dist/api/skills-service.cjs.map +1 -1
  217. package/dist/api/skills-service.d.ts +1 -1
  218. package/dist/api/skills-service.js +2 -2
  219. package/dist/api/skills-service.js.map +1 -1
  220. package/dist/components/features/backends/api-key-entry-screen.d.ts +10 -0
  221. package/dist/components/features/backends/backend-form-modal.cjs +1 -1
  222. package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
  223. package/dist/components/features/backends/backend-form-modal.d.ts +23 -2
  224. package/dist/components/features/backends/backend-form-modal.js +185 -173
  225. package/dist/components/features/backends/backend-form-modal.js.map +1 -1
  226. package/dist/components/features/browser/browser.cjs +1 -1
  227. package/dist/components/features/browser/browser.cjs.map +1 -1
  228. package/dist/components/features/browser/browser.js +10 -16
  229. package/dist/components/features/browser/browser.js.map +1 -1
  230. package/dist/components/features/conversation-panel/skills-modal.cjs +1 -1
  231. package/dist/components/features/conversation-panel/skills-modal.cjs.map +1 -1
  232. package/dist/components/features/conversation-panel/skills-modal.js +1 -1
  233. package/dist/components/features/conversation-panel/skills-modal.js.map +1 -1
  234. package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
  235. package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
  236. package/dist/components/features/mcp-page/install-server-modal.js +123 -116
  237. package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
  238. package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
  239. package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
  240. package/dist/components/features/mcp-page/installed-server-card.js +40 -40
  241. package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
  242. package/dist/components/features/mcp-page/marketplace-card.cjs +1 -1
  243. package/dist/components/features/mcp-page/marketplace-card.cjs.map +1 -1
  244. package/dist/components/features/mcp-page/marketplace-card.js +2 -3
  245. package/dist/components/features/mcp-page/marketplace-card.js.map +1 -1
  246. package/dist/components/features/mcp-page/marketplace-section.cjs +1 -1
  247. package/dist/components/features/mcp-page/marketplace-section.cjs.map +1 -1
  248. package/dist/components/features/mcp-page/marketplace-section.js +21 -21
  249. package/dist/components/features/mcp-page/marketplace-section.js.map +1 -1
  250. package/dist/components/features/onboarding/steps/setup-acp-secrets-step.d.ts +27 -0
  251. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
  252. package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +2 -0
  253. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
  254. package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs.map +1 -1
  255. package/dist/components/features/settings/sdk-settings/sdk-section-page.d.ts +10 -1
  256. package/dist/components/features/settings/sdk-settings/sdk-section-page.js +87 -84
  257. package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
  258. package/dist/constants/acp-providers.cjs +1 -1
  259. package/dist/constants/acp-providers.cjs.map +1 -1
  260. package/dist/constants/acp-providers.d.ts +25 -0
  261. package/dist/constants/acp-providers.js +1 -0
  262. package/dist/constants/acp-providers.js.map +1 -1
  263. package/dist/contexts/conversation-websocket-context.cjs +3 -3
  264. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  265. package/dist/contexts/conversation-websocket-context.js +177 -165
  266. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  267. package/dist/hooks/chat/use-model-interceptor.cjs.map +1 -1
  268. package/dist/hooks/chat/use-model-interceptor.js.map +1 -1
  269. package/dist/hooks/chat/use-slash-command.cjs +1 -1
  270. package/dist/hooks/chat/use-slash-command.cjs.map +1 -1
  271. package/dist/hooks/chat/use-slash-command.js +1 -1
  272. package/dist/hooks/chat/use-slash-command.js.map +1 -1
  273. package/dist/hooks/mutation/use-switch-llm-profile.cjs.map +1 -1
  274. package/dist/hooks/mutation/use-switch-llm-profile.d.ts +1 -1
  275. package/dist/hooks/mutation/use-switch-llm-profile.js.map +1 -1
  276. package/dist/hooks/query/use-config.cjs +1 -1
  277. package/dist/hooks/query/use-config.cjs.map +1 -1
  278. package/dist/hooks/query/use-config.js +10 -10
  279. package/dist/hooks/query/use-config.js.map +1 -1
  280. package/dist/hooks/query/use-conversation-skills.cjs +2 -0
  281. package/dist/hooks/query/use-conversation-skills.cjs.map +1 -0
  282. package/dist/hooks/query/use-conversation-skills.d.ts +7 -0
  283. package/dist/hooks/query/use-conversation-skills.js +8 -0
  284. package/dist/hooks/query/use-conversation-skills.js.map +1 -0
  285. package/dist/hooks/query/use-local-git-info.cjs +3 -3
  286. package/dist/hooks/query/use-local-git-info.cjs.map +1 -1
  287. package/dist/hooks/query/use-local-git-info.js +24 -25
  288. package/dist/hooks/query/use-local-git-info.js.map +1 -1
  289. package/dist/hooks/query/use-skills.cjs +1 -1
  290. package/dist/hooks/query/use-skills.cjs.map +1 -1
  291. package/dist/hooks/query/use-skills.d.ts +6 -1
  292. package/dist/hooks/query/use-skills.js +3 -3
  293. package/dist/hooks/query/use-skills.js.map +1 -1
  294. package/dist/i18n/declaration.cjs +1 -1
  295. package/dist/i18n/declaration.cjs.map +1 -1
  296. package/dist/i18n/declaration.d.ts +7 -0
  297. package/dist/i18n/declaration.js +1 -1
  298. package/dist/i18n/declaration.js.map +1 -1
  299. package/dist/i18n/translation.cjs +2 -2
  300. package/dist/i18n/translation.cjs.map +1 -1
  301. package/dist/i18n/translation.js +119 -0
  302. package/dist/i18n/translation.js.map +1 -1
  303. package/dist/locales/ar/openhands.json +7 -0
  304. package/dist/locales/ca/openhands.json +7 -0
  305. package/dist/locales/de/openhands.json +7 -0
  306. package/dist/locales/en/openhands.json +7 -0
  307. package/dist/locales/es/openhands.json +7 -0
  308. package/dist/locales/fr/openhands.json +7 -0
  309. package/dist/locales/it/openhands.json +7 -0
  310. package/dist/locales/ja/openhands.json +7 -0
  311. package/dist/locales/ko-KR/openhands.json +7 -0
  312. package/dist/locales/no/openhands.json +7 -0
  313. package/dist/locales/pt/openhands.json +7 -0
  314. package/dist/locales/tr/openhands.json +7 -0
  315. package/dist/locales/uk/openhands.json +7 -0
  316. package/dist/locales/zh-CN/openhands.json +7 -0
  317. package/dist/locales/zh-TW/openhands.json +7 -0
  318. package/dist/package.cjs +1 -1
  319. package/dist/package.cjs.map +1 -1
  320. package/dist/package.js +3 -3
  321. package/dist/package.js.map +1 -1
  322. package/dist/routes/conversation.cjs +1 -1
  323. package/dist/routes/conversation.cjs.map +1 -1
  324. package/dist/routes/conversation.js +61 -63
  325. package/dist/routes/conversation.js.map +1 -1
  326. package/dist/routes/mcp.cjs +1 -1
  327. package/dist/routes/mcp.cjs.map +1 -1
  328. package/dist/routes/mcp.js +64 -64
  329. package/dist/routes/mcp.js.map +1 -1
  330. package/dist/stores/browser-store.cjs +1 -1
  331. package/dist/stores/browser-store.cjs.map +1 -1
  332. package/dist/stores/browser-store.js +1 -1
  333. package/dist/stores/browser-store.js.map +1 -1
  334. package/dist/stores/use-event-store.cjs +1 -1
  335. package/dist/stores/use-event-store.cjs.map +1 -1
  336. package/dist/stores/use-event-store.d.ts +22 -0
  337. package/dist/stores/use-event-store.js +9 -1
  338. package/dist/stores/use-event-store.js.map +1 -1
  339. package/dist/ui/context-menu.d.ts +1 -1
  340. package/dist/ui/help-link.d.ts +1 -1
  341. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  342. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  343. package/dist/utils/mcp-marketplace-utils.d.ts +13 -22
  344. package/dist/utils/mcp-marketplace-utils.js +46 -28
  345. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  346. package/dist/utils/sdk-settings-schema.cjs +1 -1
  347. package/dist/utils/sdk-settings-schema.cjs.map +1 -1
  348. package/dist/utils/sdk-settings-schema.d.ts +1 -0
  349. package/dist/utils/sdk-settings-schema.js +1 -1
  350. package/dist/utils/sdk-settings-schema.js.map +1 -1
  351. package/package.json +3 -3
  352. package/scripts/dev-safe.mjs +94 -57
  353. package/scripts/dev-static.mjs +2 -3
  354. package/scripts/dev-with-automation.mjs +98 -67
  355. package/scripts/static-server.mjs +77 -35
  356. package/tools/canvas_ui_tool.py +4 -0
  357. package/build/assets/acp-providers-DauuOsW9.js +0 -1
  358. package/build/assets/add-backend-modal-KMmPQNZU.js +0 -1
  359. package/build/assets/agent-server-client-options-DT2GP6VJ.js +0 -1
  360. package/build/assets/agent-server-compatibility-2aOx5iWd.js +0 -1
  361. package/build/assets/agent-server-conversation-service.api-DSl9G5UR.js +0 -5
  362. package/build/assets/backend-form-modal-K6IMCr3p.js +0 -1
  363. package/build/assets/browser-DKG63inJ.js +0 -5
  364. package/build/assets/browser-store-C3AqxAO7.js +0 -1
  365. package/build/assets/browser-tab-B_BuTvrO.js +0 -1
  366. package/build/assets/conversation-BD5WemJI.js +0 -19
  367. package/build/assets/conversation-C47K62n8.js +0 -1
  368. package/build/assets/conversation-panel-Dn-S56Gk.js +0 -1
  369. package/build/assets/conversation-websocket-context-Ywrxd_9p.js +0 -3
  370. package/build/assets/declaration-D378OjpZ.js +0 -1
  371. package/build/assets/files-tab-B3A1NDlZ.js +0 -1
  372. package/build/assets/git-control-bar-branch-button-CcIpmyfM.js +0 -27
  373. package/build/assets/home-dIzxi5Dd.js +0 -1
  374. package/build/assets/install-server-modal-z5VaHeXd.js +0 -1
  375. package/build/assets/llm-settings-2036m7Wt.js +0 -1
  376. package/build/assets/llm-settings-CcHqGOYL.js +0 -1
  377. package/build/assets/manifest-97e839da.js +0 -1
  378. package/build/assets/mcp-C06YssEI.js +0 -9
  379. package/build/assets/root-BS1Td78t.js +0 -2
  380. package/build/assets/sdk-section-page-CJW0G04-.js +0 -1
  381. package/build/assets/secrets-settings-MLXqOtX2.js +0 -1
  382. package/build/assets/use-active-conversation-D15D9GgR.js +0 -1
  383. package/build/assets/use-config-BSu_53GL.js +0 -1
  384. package/build/assets/use-conversation-id-DajhCn2A.js +0 -1
  385. package/build/assets/use-is-authed-hXC8vxgT.js +0 -1
  386. package/build/assets/use-runtime-is-ready-XFbT16BD.js +0 -1
  387. package/build/assets/use-skills-Xe0vjPMt.js +0 -1
  388. package/build/assets/use-unified-vscode-url-BOsIOd-b.js +0 -1
  389. package/build/assets/use-user-conversation-Mc0mQgkl.js +0 -1
  390. /package/build/assets/{automation-XLxhq3I8.js → automation-IdgZq6ZK.js} +0 -0
  391. /package/build/assets/{common-SMkEaBSr.js → common-DR1t-EeP.js} +0 -0
  392. /package/build/assets/{conversation-state-store-Bc0slAjL.js → conversation-state-store-u5jepov0.js} +0 -0
  393. /package/build/assets/{dist-yMQV8IUk.js → dist-BxBP7tFD.js} +0 -0
  394. /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DnL9OC8_.js} +0 -0
  395. /package/build/assets/{handle-capture-consent-BfZATzpI.js → handle-capture-consent-3XrjZ8wi.js} +0 -0
  396. /package/build/assets/{iconBase-C7N9pPOs.js → iconBase-DE30Zj_-.js} +0 -0
  397. /package/build/assets/{settings-D5am1n6X.js → settings-D_H-qsRm.js} +0 -0
  398. /package/build/assets/{settings-like-page-layout-classes-Bn-M9oOa.js → settings-like-page-layout-classes-I0BDBEoq.js} +0 -0
  399. /package/build/assets/{settings-utils-BsvSU3OM.js → settings-utils-B6Nl07io.js} +0 -0
  400. /package/build/assets/{sidebar-store-cOeaKmIm.js → sidebar-store-Uy3v0AOV.js} +0 -0
  401. /package/build/assets/{use-breakpoint-B86yKT9n.js → use-breakpoint-DbJ6FkQ-.js} +0 -0
  402. /package/build/assets/{use-click-outside-element-835W9pC6.js → use-click-outside-element-DffgWWoZ.js} +0 -0
  403. /package/build/assets/{vendor~browser-BpdPBhgZ.js → vendor~browser-DDiZgqD3.js} +0 -0
  404. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-Df7_G0zR.js → vendor~conversation-panel~conversation~alert-banner-DbvX3OcM.js} +0 -0
  405. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~b4cctr4k-B7YVdv1X.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~g56ukk6u-DsSvIDZQ.js} +0 -0
  406. /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~i9dbt75i-CI82Did1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~hkqzh1hb-BZ0HXuHD.js} +0 -0
  407. /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~pfbaerbd-zhv9fooy.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-D9P8e98a.js} +0 -0
  408. /package/build/assets/{vendor~terminal-BUxzHKcC.js → vendor~terminal-DUrOWGFE.js} +0 -0
  409. /package/build/assets/{vscode-url-helper-jesbpos5.js → vscode-url-helper-Cwy1A62q.js} +0 -0
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "처음부터 시작",
35
35
  "HOME$READ_THIS": "이것을 읽어보세요",
36
36
  "AUTH$LOGGING_BACK_IN": "OpenHands에 다시 로그인 중...",
37
+ "AUTH$INVALID_KEY": "잘못된 API 키입니다. 키를 확인하고 다시 시도하세요.",
38
+ "AUTH$CONNECTION_FAILED": "연결 실패",
37
39
  "SECURITY$LOW_RISK": "위험: 낮음",
38
40
  "SECURITY$MEDIUM_RISK": "위험: 중간",
39
41
  "SECURITY$HIGH_RISK": "위험: 높음",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "OpenHands가 무엇을 할 수 있는지 설명하는 간단한 웹페이지를 만들어 줘",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "보내기",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "대화를 시작하는 중…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "API 키 추가",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "{{provider}} 실행에 필요한 자격 증명을 저장합니다. 비밀로 저장되며 설정 → 비밀에서 언제든지 관리할 수 있습니다.",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "에이전트 인증에 사용됩니다. 백엔드에 이미 설정된 자격 증명을 사용하려면 비워 두세요.",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "선택 사항. 프록시나 게이트웨이 등 사용자 지정 API 엔드포인트로 에이전트를 연결합니다.",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "이미 저장됨 — 유지하려면 비워 두세요",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "기존 프로필을 로드하지 못했습니다. 다시 시도하세요.",
1623
1630
  "SIDEBAR$INTEGRATIONS": "통합",
1624
1631
  "BACKEND$LOCAL_ROW": "로컬",
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "Start fra bunnen",
35
35
  "HOME$READ_THIS": "Les dette",
36
36
  "AUTH$LOGGING_BACK_IN": "Logger inn igjen på OpenHands...",
37
+ "AUTH$INVALID_KEY": "Ugyldig API-nøkkel. Sjekk nøkkelen og prøv igjen.",
38
+ "AUTH$CONNECTION_FAILED": "Tilkobling mislyktes",
37
39
  "SECURITY$LOW_RISK": "Risiko: Lav",
38
40
  "SECURITY$MEDIUM_RISK": "Risiko: Middels",
39
41
  "SECURITY$HIGH_RISK": "Risiko: Høy",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "Lag en enkel nettside som forklarer hva OpenHands kan gjøre",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "Send",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "Starter samtale…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "Legg til API-nøklene dine",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "Lagre legitimasjonen {{provider}} trenger for å kjøre. De lagres som hemmeligheter du kan administrere når som helst under Innstillinger → Hemmeligheter.",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "Brukes til å autentisere agenten. La stå tom for å bruke legitimasjon som allerede er satt opp på backend-en.",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "Valgfritt. Pek agenten mot et egendefinert API-endepunkt, for eksempel en proxy eller gateway.",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "Allerede lagret – la stå tom for å beholde",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "Kunne ikke laste eksisterende profil. Vennligst prøv igjen.",
1623
1630
  "SIDEBAR$INTEGRATIONS": "Integrasjoner",
1624
1631
  "BACKEND$LOCAL_ROW": "Lokal",
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "Começar do zero",
35
35
  "HOME$READ_THIS": "Leia isto",
36
36
  "AUTH$LOGGING_BACK_IN": "Entrando novamente no OpenHands...",
37
+ "AUTH$INVALID_KEY": "Chave de API inválida. Verifique a chave e tente novamente.",
38
+ "AUTH$CONNECTION_FAILED": "Falha na conexão",
37
39
  "SECURITY$LOW_RISK": "Risco: Baixo",
38
40
  "SECURITY$MEDIUM_RISK": "Risco: Médio",
39
41
  "SECURITY$HIGH_RISK": "Risco: Alto",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "Crie uma página web básica explicando o que o OpenHands pode fazer",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "Enviar",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "Iniciando conversa…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "Adicione suas chaves de API",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "Guarde as credenciais que o {{provider}} precisa para funcionar. Elas são salvas como segredos que você pode gerenciar a qualquer momento em Configurações → Segredos.",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "Usada para autenticar o agente. Deixe em branco para usar as credenciais já configuradas no seu backend.",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "Opcional. Aponte o agente para um endpoint de API personalizado, como um proxy ou gateway.",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "Já salvo — deixe em branco para manter",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "Falha ao carregar o perfil existente. Por favor, tente novamente.",
1623
1630
  "SIDEBAR$INTEGRATIONS": "Integrações",
1624
1631
  "BACKEND$LOCAL_ROW": "Local",
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "Sıfırdan başla",
35
35
  "HOME$READ_THIS": "Bunu oku",
36
36
  "AUTH$LOGGING_BACK_IN": "OpenHands'e yeniden giriş yapılıyor...",
37
+ "AUTH$INVALID_KEY": "Geçersiz API anahtarı. Lütfen anahtarı kontrol edin ve tekrar deneyin.",
38
+ "AUTH$CONNECTION_FAILED": "Bağlantı başarısız",
37
39
  "SECURITY$LOW_RISK": "Risk: Düşük",
38
40
  "SECURITY$MEDIUM_RISK": "Risk: Orta",
39
41
  "SECURITY$HIGH_RISK": "Risk: Yüksek",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "OpenHands'in neler yapabileceğini anlatan basit bir web sayfası oluştur",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "Gönder",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "Sohbet başlatılıyor…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "API anahtarlarınızı ekleyin",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "{{provider}} öğesinin çalışması için gereken kimlik bilgilerini saklayın. Bunlar, Ayarlar → Gizli Bilgiler altında istediğiniz zaman yönetebileceğiniz gizli bilgiler olarak kaydedilir.",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "Aracıyı doğrulamak için kullanılır. Arka uçta zaten ayarlanmış kimlik bilgilerini kullanmak için boş bırakın.",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "İsteğe bağlı. Aracıyı proxy veya ağ geçidi gibi özel bir API uç noktasına yönlendirin.",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "Zaten kaydedildi — korumak için boş bırakın",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "Mevcut profil yüklenemedi. Lütfen tekrar deneyin.",
1623
1630
  "SIDEBAR$INTEGRATIONS": "Entegrasyonlar",
1624
1631
  "BACKEND$LOCAL_ROW": "Yerel",
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "Почати з нуля",
35
35
  "HOME$READ_THIS": "Прочитайте це",
36
36
  "AUTH$LOGGING_BACK_IN": "Повторний вхід до OpenHands...",
37
+ "AUTH$INVALID_KEY": "Недійсний ключ API. Перевірте ключ і спробуйте ще раз.",
38
+ "AUTH$CONNECTION_FAILED": "Помилка з'єднання",
37
39
  "SECURITY$LOW_RISK": "Ризик: Низький",
38
40
  "SECURITY$MEDIUM_RISK": "Ризик: Середній",
39
41
  "SECURITY$HIGH_RISK": "Ризик: Високий",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "Створи просту вебсторінку, що пояснює, на що здатний OpenHands",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "Надіслати",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "Розпочинаємо розмову…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "Додайте свої ключі API",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "Збережіть облікові дані, потрібні для роботи {{provider}}. Вони зберігаються як секрети, якими можна керувати будь-коли в розділі Налаштування → Секрети.",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "Використовується для автентифікації агента. Залиште порожнім, щоб використати облікові дані, уже налаштовані на вашому бекенді.",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "Необов'язково. Спрямуйте агента на власну кінцеву точку API, наприклад проксі або шлюз.",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "Уже збережено — залиште порожнім, щоб зберегти",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "Не вдалося завантажити існуючий профіль. Будь ласка, спробуйте ще раз.",
1623
1630
  "SIDEBAR$INTEGRATIONS": "Інтеграції",
1624
1631
  "BACKEND$LOCAL_ROW": "Локальний",
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "从零开始",
35
35
  "HOME$READ_THIS": "阅读此内容",
36
36
  "AUTH$LOGGING_BACK_IN": "正在重新登录OpenHands...",
37
+ "AUTH$INVALID_KEY": "无效的API密钥。请检查密钥后重试。",
38
+ "AUTH$CONNECTION_FAILED": "连接失败",
37
39
  "SECURITY$LOW_RISK": "风险: 低",
38
40
  "SECURITY$MEDIUM_RISK": "风险: 中等",
39
41
  "SECURITY$HIGH_RISK": "风险: 高",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "创建一个简单的网页,说明 OpenHands 能做什么",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "发送",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "正在开始对话…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "添加你的 API 密钥",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "保存 {{provider}} 运行所需的凭据。它们将作为密钥保存,你可以随时在“设置 → 密钥”中管理。",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "用于对智能体进行身份验证。如果要使用后端已配置的凭据,请留空。",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "可选。让智能体指向自定义 API 端点,例如代理或网关。",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "已保存 — 留空以保留",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "无法加载现有配置文件。请重试。",
1623
1630
  "SIDEBAR$INTEGRATIONS": "集成",
1624
1631
  "BACKEND$LOCAL_ROW": "本地",
@@ -34,6 +34,8 @@
34
34
  "HOME$LAUNCH_FROM_SCRATCH": "從零開始",
35
35
  "HOME$READ_THIS": "閱讀此內容",
36
36
  "AUTH$LOGGING_BACK_IN": "正在重新登錄OpenHands...",
37
+ "AUTH$INVALID_KEY": "無效的API金鑰。請檢查金鑰後重試。",
38
+ "AUTH$CONNECTION_FAILED": "連線失敗",
37
39
  "SECURITY$LOW_RISK": "風險: 低",
38
40
  "SECURITY$MEDIUM_RISK": "風險: 中等",
39
41
  "SECURITY$HIGH_RISK": "風險: 高",
@@ -1619,6 +1621,11 @@
1619
1621
  "ONBOARDING$HELLO_DEFAULT_MESSAGE": "建立一個簡單的網頁,說明 OpenHands 能做什麼",
1620
1622
  "ONBOARDING$HELLO_LAUNCH": "傳送",
1621
1623
  "ONBOARDING$HELLO_LAUNCHING": "對話開始中…",
1624
+ "ONBOARDING$ACP_SECRETS_TITLE": "新增你的 API 金鑰",
1625
+ "ONBOARDING$ACP_SECRETS_SUBTITLE": "儲存 {{provider}} 執行所需的憑證。它們會以密鑰形式保存,你可以隨時在「設定 → 密鑰」中管理。",
1626
+ "ONBOARDING$ACP_SECRET_API_KEY_HINT": "用於驗證代理。若要使用後端已設定的憑證,請留空。",
1627
+ "ONBOARDING$ACP_SECRET_BASE_URL_HINT": "選填。讓代理指向自訂 API 端點,例如代理伺服器或閘道。",
1628
+ "ONBOARDING$ACP_SECRET_ALREADY_SET": "已儲存 — 留空以保留",
1622
1629
  "ERROR$FAILED_TO_LOAD_PROFILE_TRY_AGAIN": "無法載入現有設定檔。請重試。",
1623
1630
  "SIDEBAR$INTEGRATIONS": "整合",
1624
1631
  "BACKEND$LOCAL_ROW": "本機",
@@ -30,9 +30,5 @@
30
30
  "automation": "openhands-automation",
31
31
  "tools": "openhands-tools",
32
32
  "workspace": "openhands-workspace"
33
- },
34
-
35
- "defaults": {
36
- "secretKey": "openhands-dev-secret-key-change-in-prod"
37
33
  }
38
34
  }
@@ -1,5 +1,5 @@
1
1
  require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./agent-server-config.cjs`),t=require(`./backend-registry/active-store.cjs`),n=require(`./backend-registry/auth.cjs`),r=require(`./agent-server-client-options.cjs`),i=require(`./conversation-metadata-store.cjs`),a=require(`../services/settings.cjs`),o=require(`../types/agent-server/core/base/common.cjs`),s=require(`../constants/acp-providers.cjs`),c=require(`./agent-server-compatibility.cjs`),l=require(`./settings-service/settings-service.api.cjs`);var u=`canvas_ui`,d=`canvas_ui_tool`,f=[`terminal`,`file_editor`,`task_tracker`,u],p=`browser_tool_set`,m=`task_tool_set`;function h(){return!0}function g(){let e=(void 0)?.trim();if(!e)return null;try{let t=JSON.parse(e);return!t||typeof t!=`object`?null:t}catch{return null}}function _(){let e=g();if(!e?.services)return;let t=[];t.push(`<RUNTIME_SERVICES>`),e.mode?t.push(`You are running inside an agent-canvas dev stack started in '${e.mode}' mode.`):t.push(`You are running inside an agent-canvas dev stack.`),t.push(`The following services are reachable from your sandbox. URLs are written`,`from your point of view (i.e., as you should curl/fetch them).`,``);let{agent_server:n,ingress:r,automation:i}=e.services,a=e.services.frontend??e.services.vite;n?.url_from_agent&&t.push(`* Agent Server (you): ${n.url_from_agent}`,` ${n.description??`The agent-server hosting your tool calls.`}`),r?.url_from_agent&&t.push(`* Ingress: ${r.url_from_agent}`,` ${r.description??`Unified entry point for browser-facing traffic.`}`),a?.url_from_agent&&t.push(`* Frontend: ${a.url_from_agent}`,` ${a.description??`Frontend dev server.`}`),i?.url_from_agent?(t.push(`* Automation backend: ${i.url_from_agent}`,` ${i.description??`OpenHands Automations service.`}`),i.docs_url&&t.push(` Docs: ${i.docs_url}`),i.openapi_url&&t.push(` OpenAPI: ${i.openapi_url}`),i.auth_env_var&&t.push(` Auth: header 'X-API-Key: $${i.auth_env_var}'`)):t.push(`* Automation backend: not running in this dev mode (skip /api/automation calls).`);let o=n?.url_from_agent;return t.push(``,`Trust this block over guessing: do not assume any other URLs are running.`),o&&t.push(`In particular, ${o} inside your sandbox is the Agent Server`,`you are running inside of — NOT the automation backend.`),t.push(`</RUNTIME_SERVICES>`),t.join(`
2
2
  `)}function v(e){let{host:t}=r.getAgentServerClientOptions();return`${t}/api/conversations/${e}`}function y(e){return`Conversation ${e.slice(0,5)}`}function b(t){let n=i.getStoredConversationMetadata(t.id),c=t.agent?.kind===`ACPAgent`,l=c?t.tags?.acpserver??null:null;return{id:t.id,created_by_user_id:null,selected_repository:n?.selected_repository??null,selected_branch:n?.selected_branch??null,git_provider:n?.git_provider??null,selected_workspace:n?.selected_workspace??null,title:t.title?.trim()?t.title:y(t.id),trigger:null,pr_number:[],agent_kind:c?`acp`:`openhands`,acp_server:l,llm_model:c?s.resolveEffectiveAcpModel({runtimeName:t.current_model_name,runtimeId:t.current_model_id,configured:t.agent?.acp_model,sdkLlm:t.agent?.llm?.model}):t.agent?.llm?.model??a.DEFAULT_SETTINGS.llm_model,metrics:t.metrics?{accumulated_cost:t.metrics.accumulated_cost??null,max_budget_per_task:t.metrics.max_budget_per_task??null,accumulated_token_usage:t.metrics.accumulated_token_usage?{prompt_tokens:t.metrics.accumulated_token_usage.prompt_tokens??0,completion_tokens:t.metrics.accumulated_token_usage.completion_tokens??0,cache_read_tokens:t.metrics.accumulated_token_usage.cache_read_tokens??0,cache_write_tokens:t.metrics.accumulated_token_usage.cache_write_tokens??0,context_window:t.metrics.accumulated_token_usage.context_window??0,per_turn_token:t.metrics.accumulated_token_usage.per_turn_token??0}:null}:null,created_at:t.created_at,updated_at:t.updated_at,execution_status:t.execution_status??o.ExecutionStatus.IDLE,sandbox_status:t.sandbox_status??null,conversation_url:v(t.id),session_api_key:r.getAgentServerClientOptions().apiKey??null,sandbox_id:null,workspace:{working_dir:t.workspace?.working_dir??e.getAgentServerWorkingDir()},public:!1,sub_conversation_ids:[]}}function x(e){return{items:e.items.map(b),next_page_id:e.next_page_id??null}}var S=[`acp_command`,`acp_args`,`acp_env`,`acp_model`,`acp_session_mode`,`acp_prompt_timeout`],C=`acpserver`,w=new Set([`schema_version`,`agent_settings`,`workspace`,`conversation_id`,`initial_message`,`plugins`]);function T(e){return!e||typeof e!=`object`||Array.isArray(e)?{}:structuredClone(e)}function E(e){if(typeof e!=`string`)return;let t=e.trim();return t.length>0?t:void 0}function D(e){return e.confirmation_mode===!0?e.security_analyzer===`llm`?{kind:`ConfirmRisky`,threshold:`HIGH`,confirm_unknown:!0}:{kind:`AlwaysConfirm`}:{kind:`NeverConfirm`}}function O(e){switch(e.security_analyzer){case`llm`:return{kind:`LLMSecurityAnalyzer`};case`pattern`:return{kind:`PatternSecurityAnalyzer`};case`policy_rail`:return{kind:`PolicyRailSecurityAnalyzer`};default:return}}function k(e){return!!e&&typeof e==`object`&&!Array.isArray(e)&&typeof e.name==`string`}function A(e,t){return e===p?h()&&c.isAgentServerToolAvailable(e):e===m?t.enable_sub_agents===!0&&c.isAgentServerToolAvailable(e):!0}function j(e){let t=new Map;for(let e of f)t.set(e,{name:e,params:{}});for(let n of[p,m])A(n,e)&&t.set(n,{name:n,params:{}});let n=e.tools;if(Array.isArray(n)&&n.every(e=>k(e)))for(let r of n)A(r.name,e)&&t.set(r.name,{name:r.name,params:T(r.params)});return Array.from(t.values())}function M(e,t){let n=[e?.trim(),t?.trim()].filter(Boolean);return n.length===0?null:{role:`user`,content:[{type:`text`,text:n.join(`
3
3
 
4
- `)}],run:!0}}function N(t){let n=_();return{...T(t.agent_context),load_public_skills:e.shouldLoadPublicSkills(),load_user_skills:!0,...n?{system_message_suffix:n}:{}}}function P(e){return T(e.agent_settings).agent_kind===`acp`}function F(e){let t=T(e.agent_settings).acp_server;return typeof t==`string`&&t.length>0?t:void 0}function I(e){let t=e.acp_command;if(!(Array.isArray(t)&&t.length===0)&&t!==void 0)return t;let n=s.getAcpProvider(typeof e.acp_server==`string`?e.acp_server:void 0);return n?[...n.default_command]:t}function L(e){let t=T(e.agent_settings),n={agent_kind:`acp`,agent_context:N(t)};for(let e of S){if(e===`acp_model`)continue;let r=e===`acp_command`?I(t):t[e];r!=null&&(n[e]=r)}let r=s.getAcpProvider(typeof t.acp_server==`string`?t.acp_server:void 0),i=s.resolveEffectiveAcpModel({configured:t.acp_model,providerDefault:r?.default_model});return i&&(n.acp_model=i),n}function R(e){let t=T(e.agent_settings),n=T(t.llm);n.model=typeof n.model==`string`?n.model:a.DEFAULT_SETTINGS.llm_model;let r=E(n.api_key);r?n.api_key=r:delete n.api_key;let i=E(n.base_url);i?n.base_url=i:delete n.base_url;let o=T(t.mcp_config);(Object.keys(o).length===0||!(`mcpServers`in o))&&delete t.mcp_config,delete t.acp_server;for(let e of S)delete t[e];return{...t,llm:n,agent_context:N(t),tools:j(t)}}function z(e){return P(e)?L(e):R(e)}function B(t){let{settings:n,query:r,conversationInstructions:i,plugins:a,workingDir:o}=t,s=T(n.conversation_settings),c=M(r,i);return w.forEach(e=>delete s[e]),{...s,workspace:{kind:`LocalWorkspace`,working_dir:o??e.getAgentServerWorkingDir()},...c?{initial_message:c}:{},...a?.length?{plugins:a.map(e=>({source:e.source,...e.ref?{ref:e.ref}:{},...e.repo_path?{repo_path:e.repo_path}:{}}))}:{}}}function V(e){let r=e.encryptedAgentSettings?{...e.settings,agent_settings:e.encryptedAgentSettings}:e.settings,i=P(r),a=z(r),o=i?F(r):void 0,s=B(e.encryptedConversationSettings?{...e,settings:{...e.settings,conversation_settings:e.encryptedConversationSettings}}:e),c={agent_settings:a,workspace:s.workspace,confirmation_policy:D(s),max_iterations:typeof s.max_iterations==`number`?s.max_iterations:500,stuck_detection:!0,autotitle:!0,worktree:!0};o&&(c.tags={[C]:o}),e.secretsEncrypted&&(c.secrets_encrypted=!0),e.conversationId&&(c.conversation_id=e.conversationId);let l=O(s);if(l&&(c.security_analyzer=l),s.initial_message&&(c.initial_message=s.initial_message),s.plugins&&(c.plugins=s.plugins),s.hook_config&&(c.hook_config=s.hook_config),c.tool_module_qualnames={[u]:d,...s.tool_module_qualnames??{}},s.agent_definitions&&(c.agent_definitions=s.agent_definitions),e.customSecrets&&e.customSecrets.length>0){let r=n.buildAuthHeaders(t.getEffectiveLocalBackend()),a={};for(let t of e.customSecrets){let e={kind:`LookupSecret`,url:`/api/settings/secrets/${encodeURIComponent(t.name)}`,description:t.description};Object.keys(r).length>0&&(e.headers=r),a[t.name]=e}c.secrets=a,i&&(c.agent_settings.agent_context={...c.agent_settings.agent_context,secrets:a})}return c}async function H(e){let{SecretsService:t}=await Promise.resolve().then(()=>require(`./secrets-service.cjs`)),[n,r]=await Promise.all([l.default.getSettingsForConversation(),t.getSecrets()]),{agentSettings:i,conversationSettings:a,secretsEncrypted:o}=n;return V({...e,encryptedAgentSettings:i,encryptedConversationSettings:a,secretsEncrypted:o,customSecrets:r})}function U(){return{hooks:[]}}exports.buildStartConversationRequestWithEncryptedSettings=H,exports.emptyHooksResponse=U,exports.getDefaultConversationTitle=y,exports.toAppConversation=b,exports.toConversationPage=x;
4
+ `)}],run:!0}}function N(t){let n=_();return{...T(t.agent_context),load_public_skills:e.shouldLoadPublicSkills(),load_user_skills:!0,load_project_skills:!0,...n?{system_message_suffix:n}:{}}}function P(e){return T(e.agent_settings).agent_kind===`acp`}function F(e){let t=T(e.agent_settings).acp_server;return typeof t==`string`&&t.length>0?t:void 0}function I(e){let t=e.acp_command;if(!(Array.isArray(t)&&t.length===0)&&t!==void 0)return t;let n=s.getAcpProvider(typeof e.acp_server==`string`?e.acp_server:void 0);return n?[...n.default_command]:t}function L(e){let t=T(e.agent_settings),n={agent_kind:`acp`,agent_context:N(t)};for(let e of S){if(e===`acp_model`)continue;let r=e===`acp_command`?I(t):t[e];r!=null&&(n[e]=r)}let r=s.getAcpProvider(typeof t.acp_server==`string`?t.acp_server:void 0),i=s.resolveEffectiveAcpModel({configured:t.acp_model,providerDefault:r?.default_model});return i&&(n.acp_model=i),n}function R(e){let t=T(e.agent_settings),n=T(t.llm);n.model=typeof n.model==`string`&&n.model.trim().length>0?n.model:a.DEFAULT_SETTINGS.llm_model;let r=E(n.api_key);r?n.api_key=r:delete n.api_key;let i=E(n.base_url);i?n.base_url=i:delete n.base_url;let o=T(t.mcp_config);(Object.keys(o).length===0||!(`mcpServers`in o))&&delete t.mcp_config,delete t.acp_server;for(let e of S)delete t[e];return{...t,llm:n,agent_context:N(t),tools:j(t)}}function z(e){return P(e)?L(e):R(e)}function B(t){let{settings:n,query:r,conversationInstructions:i,plugins:a,workingDir:o}=t,s=T(n.conversation_settings),c=M(r,i);return w.forEach(e=>delete s[e]),{...s,workspace:{kind:`LocalWorkspace`,working_dir:o??e.getAgentServerWorkingDir()},...c?{initial_message:c}:{},...a?.length?{plugins:a.map(e=>({source:e.source,...e.ref?{ref:e.ref}:{},...e.repo_path?{repo_path:e.repo_path}:{}}))}:{}}}function V(e){let r=e.encryptedAgentSettings?{...e.settings,agent_settings:e.encryptedAgentSettings}:e.settings,i=P(r),a=z(r),o=i?F(r):void 0,s=B(e.encryptedConversationSettings?{...e,settings:{...e.settings,conversation_settings:e.encryptedConversationSettings}}:e),c={agent_settings:a,workspace:s.workspace,confirmation_policy:D(s),max_iterations:typeof s.max_iterations==`number`?s.max_iterations:500,stuck_detection:!0,autotitle:!0,worktree:!0};o&&(c.tags={[C]:o}),e.secretsEncrypted&&(c.secrets_encrypted=!0),e.conversationId&&(c.conversation_id=e.conversationId);let l=O(s);if(l&&(c.security_analyzer=l),s.initial_message&&(c.initial_message=s.initial_message),s.plugins&&(c.plugins=s.plugins),s.hook_config&&(c.hook_config=s.hook_config),c.tool_module_qualnames={[u]:d,...s.tool_module_qualnames??{}},s.agent_definitions&&(c.agent_definitions=s.agent_definitions),e.customSecrets&&e.customSecrets.length>0){let r=n.buildAuthHeaders(t.getEffectiveLocalBackend()),a={};for(let t of e.customSecrets){let e={kind:`LookupSecret`,url:`/api/settings/secrets/${encodeURIComponent(t.name)}`,description:t.description};Object.keys(r).length>0&&(e.headers=r),a[t.name]=e}c.secrets=a,i&&(c.agent_settings.agent_context={...c.agent_settings.agent_context,secrets:a})}return c}async function H(e){let{SecretsService:t}=await Promise.resolve().then(()=>require(`./secrets-service.cjs`)),[n,r]=await Promise.all([l.default.getSettingsForConversation(),t.getSecrets()]),{agentSettings:i,conversationSettings:a,secretsEncrypted:o}=n;return V({...e,encryptedAgentSettings:i,encryptedConversationSettings:a,secretsEncrypted:o,customSecrets:r})}function U(){return{hooks:[]}}exports.buildStartConversationRequestWithEncryptedSettings=H,exports.emptyHooksResponse=U,exports.getDefaultConversationTitle=y,exports.toAppConversation=b,exports.toConversationPage=x;
5
5
  //# sourceMappingURL=agent-server-adapter.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-server-adapter.cjs","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport {\n getAgentServerWorkingDir,\n shouldLoadPublicSkills,\n} from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of `VITE_RUNTIME_SERVICES_INFO` (set by the dev launchers in\n * scripts/dev-*.mjs). All URLs are written from the agent's point of view,\n * not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured dev env var.\n return null;\n }\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n lines.push(\n ` Auth: header 'X-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nconst ACP_SETTINGS_KEYS = [\n \"acp_command\",\n \"acp_args\",\n \"acp_env\",\n \"acp_model\",\n \"acp_session_mode\",\n \"acp_prompt_timeout\",\n] as const;\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n return {\n ...toRecord(agentSettings.agent_context),\n load_public_skills: shouldLoadPublicSkills(),\n load_user_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the provider's ``default_model`` so the conversation starts\n // with whatever the Settings → Agent UI shows — without that, the form's\n // displayed default would silently not take effect at runtime until the\n // user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: provider?.default_model,\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" ? llm.model : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: true;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n if (options.secretsEncrypted) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = buildAuthHeaders(backend);\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n\n if (acpMode) {\n payload.agent_settings.agent_context = {\n ...payload.agent_settings.agent_context,\n secrets,\n };\n }\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-server-adapter.cjs","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport {\n getAgentServerWorkingDir,\n shouldLoadPublicSkills,\n} from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of `VITE_RUNTIME_SERVICES_INFO` (set by the dev launchers in\n * scripts/dev-*.mjs). All URLs are written from the agent's point of view,\n * not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured dev env var.\n return null;\n }\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n lines.push(\n ` Auth: header 'X-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nconst ACP_SETTINGS_KEYS = [\n \"acp_command\",\n \"acp_args\",\n \"acp_env\",\n \"acp_model\",\n \"acp_session_mode\",\n \"acp_prompt_timeout\",\n] as const;\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n return {\n ...toRecord(agentSettings.agent_context),\n load_public_skills: shouldLoadPublicSkills(),\n load_user_skills: true,\n load_project_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the provider's ``default_model`` so the conversation starts\n // with whatever the Settings → Agent UI shows — without that, the form's\n // displayed default would silently not take effect at runtime until the\n // user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: provider?.default_model,\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" && llm.model.trim().length > 0\n ? llm.model\n : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: true;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n if (options.secretsEncrypted) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = buildAuthHeaders(backend);\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n\n if (acpMode) {\n payload.agent_settings.agent_context = {\n ...payload.agent_settings.agent_context,\n secrets,\n };\n }\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
@@ -173,6 +173,7 @@ function F(e) {
173
173
  ...D(e.agent_context),
174
174
  load_public_skills: t(),
175
175
  load_user_skills: !0,
176
+ load_project_skills: !0,
176
177
  ...n ? { system_message_suffix: n } : {}
177
178
  };
178
179
  }
@@ -207,7 +208,7 @@ function z(e) {
207
208
  }
208
209
  function B(e) {
209
210
  let t = D(e.agent_settings), n = D(t.llm);
210
- n.model = typeof n.model == "string" ? n.model : o.llm_model;
211
+ n.model = typeof n.model == "string" && n.model.trim().length > 0 ? n.model : o.llm_model;
211
212
  let r = O(n.api_key);
212
213
  r ? n.api_key = r : delete n.api_key;
213
214
  let i = O(n.base_url);
@@ -1 +1 @@
1
- {"version":3,"file":"agent-server-adapter.js","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport {\n getAgentServerWorkingDir,\n shouldLoadPublicSkills,\n} from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of `VITE_RUNTIME_SERVICES_INFO` (set by the dev launchers in\n * scripts/dev-*.mjs). All URLs are written from the agent's point of view,\n * not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured dev env var.\n return null;\n }\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n lines.push(\n ` Auth: header 'X-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nconst ACP_SETTINGS_KEYS = [\n \"acp_command\",\n \"acp_args\",\n \"acp_env\",\n \"acp_model\",\n \"acp_session_mode\",\n \"acp_prompt_timeout\",\n] as const;\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n return {\n ...toRecord(agentSettings.agent_context),\n load_public_skills: shouldLoadPublicSkills(),\n load_user_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the provider's ``default_model`` so the conversation starts\n // with whatever the Settings → Agent UI shows — without that, the form's\n // displayed default would silently not take effect at runtime until the\n // user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: provider?.default_model,\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" ? llm.model : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: true;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n if (options.secretsEncrypted) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = buildAuthHeaders(backend);\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n\n if (acpMode) {\n payload.agent_settings.agent_context = {\n ...payload.agent_settings.agent_context,\n secrets,\n };\n }\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"agent-server-adapter.js","names":[],"sources":["../../src/api/agent-server-adapter.ts"],"sourcesContent":["import { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport { ExecutionStatus } from \"#/types/agent-server/core\";\nimport { Settings, SettingsValue } from \"#/types/settings\";\nimport {\n getAcpProvider,\n resolveEffectiveAcpModel,\n} from \"#/constants/acp-providers\";\nimport { getAgentServerClientOptions } from \"./agent-server-client-options\";\nimport { isAgentServerToolAvailable } from \"./agent-server-compatibility\";\nimport {\n getAgentServerWorkingDir,\n shouldLoadPublicSkills,\n} from \"./agent-server-config\";\nimport { getEffectiveLocalBackend } from \"./backend-registry/active-store\";\nimport { buildAuthHeaders } from \"./backend-registry/auth\";\nimport {\n GetHooksResponse,\n PluginSpec,\n AppConversation,\n AppConversationPage,\n SandboxStatus,\n} from \"./conversation-service/agent-server-conversation-service.types\";\nimport SettingsService from \"./settings-service/settings-service.api\";\nimport { getStoredConversationMetadata } from \"./conversation-metadata-store\";\n\nexport interface DirectConversationInfo {\n id: string;\n title?: string | null;\n created_at: string;\n updated_at: string;\n execution_status?: string | null;\n /** Cloud-only sandbox lifecycle state. Omitted / null for local agent-server conversations. */\n sandbox_status?: string | null;\n metrics?: {\n accumulated_cost?: number | null;\n max_budget_per_task?: number | null;\n accumulated_token_usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n cache_read_tokens?: number;\n cache_write_tokens?: number;\n context_window?: number;\n per_turn_token?: number;\n } | null;\n } | null;\n agent?: {\n /**\n * Pydantic discriminator from the SDK union: ``\"ACPAgent\"`` for ACP CLI\n * subprocesses (model lives on the subprocess via ``acp_model``),\n * ``\"Agent\"`` for direct litellm. Read by {@link toAppConversation}.\n */\n kind?: string | null;\n acp_model?: string | null;\n llm?: {\n model?: string | null;\n } | null;\n } | null;\n current_model_id?: string | null;\n current_model_name?: string | null;\n workspace?: {\n working_dir?: string | null;\n } | null;\n /**\n * Arbitrary string-keyed conversation tags surfaced by the agent-server\n * (see ``ConversationInfo.tags``). Canvas only consumes one key today —\n * ``ACP_SERVER_TAG_KEY`` (\"acpserver\") — but the field is typed as a\n * generic record so future readers don't need another wire-shape change.\n * Keys are constrained to ``^[a-z0-9]+$`` by the agent-server validator;\n * values are opaque strings.\n */\n tags?: Record<string, string> | null;\n}\n\n// Module qualname for the Canvas-UI tool. The agent-server imports this via\n// tool_module_qualnames; the host directory is exposed via OH_EXTRA_PYTHON_PATH\n// (see scripts/dev-safe.mjs).\nconst CANVAS_UI_TOOL_NAME = \"canvas_ui\";\nconst CANVAS_UI_TOOL_MODULE = \"canvas_ui_tool\";\n\nconst DEFAULT_TOOL_NAMES = [\n \"terminal\",\n \"file_editor\",\n \"task_tracker\",\n CANVAS_UI_TOOL_NAME,\n];\nconst BROWSER_TOOL_SET_NAME = \"browser_tool_set\";\nconst TASK_TOOL_SET_NAME = \"task_tool_set\";\n\nfunction browserToolsEnabled() {\n return import.meta.env.VITE_ENABLE_BROWSER_TOOLS !== \"false\";\n}\n\n/**\n * Shape of `VITE_RUNTIME_SERVICES_INFO` (set by the dev launchers in\n * scripts/dev-*.mjs). All URLs are written from the agent's point of view,\n * not the browser's. The block is rendered into the agent's system prompt\n * via `AgentContext.system_message_suffix` so the agent knows what's\n * reachable from inside its sandbox without having to probe.\n */\ninterface RuntimeServicesInfo {\n mode?: string;\n agent_host_alias?: string;\n services?: {\n agent_server?: { description?: string; url_from_agent?: string };\n ingress?: { description?: string; url_from_agent?: string };\n frontend?: {\n kind?: \"vite\" | \"static\";\n description?: string;\n url_from_agent?: string;\n };\n // `vite` is the legacy key name for the frontend entry, accepted for\n // one release while older dev-stack launchers may still emit it.\n vite?: { description?: string; url_from_agent?: string };\n automation?: {\n description?: string;\n url_from_agent?: string;\n api_prefix?: string;\n docs_url?: string;\n openapi_url?: string;\n auth_env_var?: string;\n };\n };\n}\n\nfunction parseRuntimeServicesInfo(): RuntimeServicesInfo | null {\n const raw = import.meta.env.VITE_RUNTIME_SERVICES_INFO?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as RuntimeServicesInfo;\n if (!parsed || typeof parsed !== \"object\") return null;\n return parsed;\n } catch {\n // Malformed JSON: ignore and fall back to no runtime info, rather than\n // tearing down conversation creation over a misconfigured dev env var.\n return null;\n }\n}\n\n/**\n * Render the runtime services info into a markdown block suitable for\n * appending to the system prompt via `AgentContext.system_message_suffix`.\n *\n * Returns `undefined` when no runtime info is configured, so callers can\n * safely omit the field on production builds (where the launcher doesn't\n * set `VITE_RUNTIME_SERVICES_INFO`).\n */\nexport function buildRuntimeServicesSystemSuffix(): string | undefined {\n const info = parseRuntimeServicesInfo();\n if (!info?.services) return undefined;\n\n const lines: string[] = [];\n lines.push(\"<RUNTIME_SERVICES>\");\n if (info.mode) {\n lines.push(\n `You are running inside an agent-canvas dev stack started in '${info.mode}' mode.`,\n );\n } else {\n lines.push(\"You are running inside an agent-canvas dev stack.\");\n }\n lines.push(\n \"The following services are reachable from your sandbox. URLs are written\",\n \"from your point of view (i.e., as you should curl/fetch them).\",\n \"\",\n );\n\n const { agent_server, ingress, automation } = info.services;\n // Accept `frontend` (current key) or `vite` (legacy key) for the\n // frontend service entry. The legacy fallback can be removed once all\n // launchers in this repo emit `frontend`.\n const frontend = info.services.frontend ?? info.services.vite;\n\n if (agent_server?.url_from_agent) {\n lines.push(\n `* Agent Server (you): ${agent_server.url_from_agent}`,\n ` ${agent_server.description ?? \"The agent-server hosting your tool calls.\"}`,\n );\n }\n if (ingress?.url_from_agent) {\n lines.push(\n `* Ingress: ${ingress.url_from_agent}`,\n ` ${ingress.description ?? \"Unified entry point for browser-facing traffic.\"}`,\n );\n }\n if (frontend?.url_from_agent) {\n lines.push(\n `* Frontend: ${frontend.url_from_agent}`,\n ` ${frontend.description ?? \"Frontend dev server.\"}`,\n );\n }\n if (automation?.url_from_agent) {\n lines.push(\n `* Automation backend: ${automation.url_from_agent}`,\n ` ${automation.description ?? \"OpenHands Automations service.\"}`,\n );\n if (automation.docs_url) {\n lines.push(` Docs: ${automation.docs_url}`);\n }\n if (automation.openapi_url) {\n lines.push(` OpenAPI: ${automation.openapi_url}`);\n }\n if (automation.auth_env_var) {\n lines.push(\n ` Auth: header 'X-API-Key: $${automation.auth_env_var}'`,\n );\n }\n } else {\n lines.push(\n \"* Automation backend: not running in this dev mode (skip /api/automation calls).\",\n );\n }\n\n // Anchor the \"don't guess\" warning to the actual agent-server URL for\n // this stack instead of a hardcoded port. The agent-server listens on\n // different ports across dev modes, and baking the wrong port into the\n // system prompt is exactly the kind of confusion this block is meant to\n // prevent.\n const agentServerUrl = agent_server?.url_from_agent;\n lines.push(\n \"\",\n \"Trust this block over guessing: do not assume any other URLs are running.\",\n );\n if (agentServerUrl) {\n lines.push(\n `In particular, ${agentServerUrl} inside your sandbox is the Agent Server`,\n \"you are running inside of — NOT the automation backend.\",\n );\n }\n lines.push(\"</RUNTIME_SERVICES>\");\n\n return lines.join(\"\\n\");\n}\n\nexport function toConversationUrl(conversationId: string): string {\n // Local-format conversation URL — points at whichever local agent-server\n // is actually serving the conversation (the bundled one when the active\n // selection is cloud).\n const { host } = getAgentServerClientOptions();\n return `${host}/api/conversations/${conversationId}`;\n}\n\n// TODO(i18n): extract \"Conversation\" once we add CONVERSATION$DEFAULT_TITLE\n// with `{{shortId}}` interpolation. Kept as a literal for now to keep the\n// fallback inside this pure adapter rather than fanning out to display sites.\nexport function getDefaultConversationTitle(conversationId: string): string {\n return `Conversation ${conversationId.slice(0, 5)}`;\n}\n\nexport function toAppConversation(\n info: DirectConversationInfo,\n): AppConversation {\n const metadata = getStoredConversationMetadata(info.id);\n // ACPAgent conversations carry a sentinel ``llm`` on older SDKs. Prefer the\n // runtime model fields when available, then the configured ``acp_model`` that\n // Canvas saves for built-in providers. ``agent_kind`` still gates model\n // switching, so surfacing this string is display-only.\n const isAcp = info.agent?.kind === \"ACPAgent\";\n // Only surface ``acp_server`` for ACP conversations even if the wire\n // payload accidentally carries an ``acpserver`` tag on an OpenHands\n // conversation — the chip is identity info for the ACP CLI subprocess,\n // and showing it on a non-ACP conversation would be a lie.\n const acpServer = isAcp ? (info.tags?.[ACP_SERVER_TAG_KEY] ?? null) : null;\n return {\n id: info.id,\n created_by_user_id: null,\n selected_repository: metadata?.selected_repository ?? null,\n selected_branch: metadata?.selected_branch ?? null,\n git_provider: metadata?.git_provider ?? null,\n selected_workspace: metadata?.selected_workspace ?? null,\n title: info.title?.trim()\n ? info.title\n : getDefaultConversationTitle(info.id),\n trigger: null,\n pr_number: [],\n agent_kind: isAcp ? \"acp\" : \"openhands\",\n acp_server: acpServer,\n // Chip path: no ``providerDefault`` — the chip must distinguish\n // \"no concrete model\" (fall back to the provider display name in\n // ConversationCardFooter) from \"default\" (would lie about what's\n // running on the subprocess).\n llm_model: isAcp\n ? resolveEffectiveAcpModel({\n runtimeName: info.current_model_name,\n runtimeId: info.current_model_id,\n configured: info.agent?.acp_model,\n sdkLlm: info.agent?.llm?.model,\n })\n : (info.agent?.llm?.model ?? DEFAULT_SETTINGS.llm_model),\n metrics: info.metrics\n ? {\n accumulated_cost: info.metrics.accumulated_cost ?? null,\n max_budget_per_task: info.metrics.max_budget_per_task ?? null,\n accumulated_token_usage: info.metrics.accumulated_token_usage\n ? {\n prompt_tokens:\n info.metrics.accumulated_token_usage.prompt_tokens ?? 0,\n completion_tokens:\n info.metrics.accumulated_token_usage.completion_tokens ?? 0,\n cache_read_tokens:\n info.metrics.accumulated_token_usage.cache_read_tokens ?? 0,\n cache_write_tokens:\n info.metrics.accumulated_token_usage.cache_write_tokens ?? 0,\n context_window:\n info.metrics.accumulated_token_usage.context_window ?? 0,\n per_turn_token:\n info.metrics.accumulated_token_usage.per_turn_token ?? 0,\n }\n : null,\n }\n : null,\n created_at: info.created_at,\n updated_at: info.updated_at,\n execution_status:\n (info.execution_status as AppConversation[\"execution_status\"]) ??\n ExecutionStatus.IDLE,\n sandbox_status: (info.sandbox_status as SandboxStatus | null) ?? null,\n conversation_url: toConversationUrl(info.id),\n session_api_key: getAgentServerClientOptions().apiKey ?? null,\n sandbox_id: null,\n workspace: {\n working_dir: info.workspace?.working_dir ?? getAgentServerWorkingDir(),\n },\n public: false,\n sub_conversation_ids: [],\n };\n}\n\nexport function toConversationPage(data: {\n items: DirectConversationInfo[];\n next_page_id?: string | null;\n}): AppConversationPage {\n return {\n items: data.items.map(toAppConversation),\n next_page_id: data.next_page_id ?? null,\n };\n}\n\ntype SettingsRecord = Record<string, unknown>;\n\ninterface AgentToolSpec {\n name: string;\n params: SettingsRecord;\n}\n\ntype AgentSettingsPayload = SettingsRecord & {\n llm?: SettingsRecord;\n agent_context: SettingsRecord;\n tools?: AgentToolSpec[];\n};\n\ninterface LocalWorkspacePayload {\n kind: \"LocalWorkspace\";\n working_dir: string;\n}\n\ninterface InitialMessagePayload {\n role: \"user\";\n content: Array<{ type: \"text\"; text: string }>;\n run: true;\n}\n\ntype ConversationSettingsPayload = SettingsRecord & {\n workspace: LocalWorkspacePayload;\n initial_message?: InitialMessagePayload;\n};\n\nconst ACP_SETTINGS_KEYS = [\n \"acp_command\",\n \"acp_args\",\n \"acp_env\",\n \"acp_model\",\n \"acp_session_mode\",\n \"acp_prompt_timeout\",\n] as const;\n\nexport const ACP_SERVER_TAG_KEY = \"acpserver\";\n\nconst CONVERSATION_SETTINGS_METADATA_KEYS = new Set([\n \"schema_version\",\n \"agent_settings\",\n \"workspace\",\n \"conversation_id\",\n \"initial_message\",\n \"plugins\",\n]);\n\nfunction toRecord(value: unknown): SettingsRecord {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n return structuredClone(value as SettingsRecord);\n}\n\nfunction normalizeSecretString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction getConversationConfirmationPolicy(\n conversationSettings: SettingsRecord,\n) {\n if (conversationSettings.confirmation_mode !== true) {\n return { kind: \"NeverConfirm\" };\n }\n\n if (conversationSettings.security_analyzer === \"llm\") {\n return { kind: \"ConfirmRisky\", threshold: \"HIGH\", confirm_unknown: true };\n }\n\n return { kind: \"AlwaysConfirm\" };\n}\n\nfunction getConversationSecurityAnalyzer(conversationSettings: SettingsRecord) {\n switch (conversationSettings.security_analyzer) {\n case \"llm\":\n return { kind: \"LLMSecurityAnalyzer\" };\n case \"pattern\":\n return { kind: \"PatternSecurityAnalyzer\" };\n case \"policy_rail\":\n return { kind: \"PolicyRailSecurityAnalyzer\" };\n default:\n return undefined;\n }\n}\n\nfunction isToolRecord(\n value: unknown,\n): value is { name: string; params?: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n typeof (value as { name?: unknown }).name === \"string\"\n );\n}\n\nfunction shouldIncludeTool(name: string, agentSettings: SettingsRecord) {\n if (name === BROWSER_TOOL_SET_NAME) {\n return browserToolsEnabled() && isAgentServerToolAvailable(name);\n }\n\n if (name === TASK_TOOL_SET_NAME) {\n return (\n agentSettings.enable_sub_agents === true &&\n isAgentServerToolAvailable(name)\n );\n }\n\n return true;\n}\n\nfunction getAgentTools(agentSettings: SettingsRecord): AgentToolSpec[] {\n const tools = new Map<string, AgentToolSpec>();\n\n for (const name of DEFAULT_TOOL_NAMES) {\n tools.set(name, { name, params: {} });\n }\n\n for (const name of [BROWSER_TOOL_SET_NAME, TASK_TOOL_SET_NAME]) {\n if (shouldIncludeTool(name, agentSettings)) {\n tools.set(name, { name, params: {} });\n }\n }\n\n const configuredTools = agentSettings.tools;\n if (\n Array.isArray(configuredTools) &&\n configuredTools.every((tool) => isToolRecord(tool))\n ) {\n for (const tool of configuredTools) {\n if (shouldIncludeTool(tool.name, agentSettings)) {\n tools.set(tool.name, {\n name: tool.name,\n params: toRecord(tool.params),\n });\n }\n }\n }\n\n return Array.from(tools.values());\n}\n\nfunction buildInitialMessage(\n query?: string,\n conversationInstructions?: string,\n): InitialMessagePayload | null {\n const parts = [query?.trim(), conversationInstructions?.trim()].filter(\n Boolean,\n );\n if (parts.length === 0) {\n return null;\n }\n\n return {\n role: \"user\",\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n run: true,\n };\n}\n\nfunction buildAgentContext(agentSettings: SettingsRecord): SettingsRecord {\n const runtimeServicesSuffix = buildRuntimeServicesSystemSuffix();\n return {\n ...toRecord(agentSettings.agent_context),\n load_public_skills: shouldLoadPublicSkills(),\n load_user_skills: true,\n load_project_skills: true,\n ...(runtimeServicesSuffix\n ? { system_message_suffix: runtimeServicesSuffix }\n : {}),\n };\n}\n\nfunction isAcpAgent(settings: Settings): boolean {\n const agentSettings = toRecord(settings.agent_settings);\n return agentSettings.agent_kind === \"acp\";\n}\n\nfunction getAcpServerTag(settings: Settings): string | undefined {\n const agentSettings = toRecord(settings.agent_settings);\n const value = agentSettings.acp_server;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction resolveAcpCommand(agentSettings: SettingsRecord): unknown {\n const cmd = agentSettings.acp_command;\n const isEmpty = Array.isArray(cmd) && cmd.length === 0;\n const noCommand = cmd === undefined;\n if (!isEmpty && !noCommand) {\n return cmd;\n }\n\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n return provider ? [...provider.default_command] : cmd;\n}\n\nfunction buildConfiguredAcpAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const payload: AgentSettingsPayload = {\n agent_kind: \"acp\",\n agent_context: buildAgentContext(agentSettings),\n };\n\n for (const key of ACP_SETTINGS_KEYS) {\n // ``acp_model`` is resolved separately below so a saved ``null`` still\n // falls back to the provider's default rather than being dropped.\n if (key === \"acp_model\") continue;\n const value =\n key === \"acp_command\"\n ? resolveAcpCommand(agentSettings)\n : agentSettings[key];\n if (value !== undefined && value !== null) {\n payload[key] = value;\n }\n }\n\n // Saved settings may carry ``acp_model: null`` (existing users predating\n // the default-model registry, or saved fields the agent-server stripped).\n // Fall back to the provider's ``default_model`` so the conversation starts\n // with whatever the Settings → Agent UI shows — without that, the form's\n // displayed default would silently not take effect at runtime until the\n // user re-saved the page.\n const serverKey =\n typeof agentSettings.acp_server === \"string\"\n ? agentSettings.acp_server\n : undefined;\n const provider = getAcpProvider(serverKey);\n const effectiveModel = resolveEffectiveAcpModel({\n configured: agentSettings.acp_model as string | null | undefined,\n providerDefault: provider?.default_model,\n });\n if (effectiveModel) {\n payload.acp_model = effectiveModel;\n }\n\n return payload;\n}\n\nfunction buildConfiguredOpenHandsAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n const agentSettings = toRecord(settings.agent_settings);\n const llm = toRecord(agentSettings.llm);\n\n llm.model =\n typeof llm.model === \"string\" && llm.model.trim().length > 0\n ? llm.model\n : DEFAULT_SETTINGS.llm_model;\n\n const apiKey = normalizeSecretString(llm.api_key);\n if (apiKey) {\n llm.api_key = apiKey;\n } else {\n delete llm.api_key;\n }\n\n const baseUrl = normalizeSecretString(llm.base_url);\n if (baseUrl) {\n llm.base_url = baseUrl;\n } else {\n delete llm.base_url;\n }\n\n const mcpConfig = toRecord(agentSettings.mcp_config);\n if (Object.keys(mcpConfig).length === 0 || !(\"mcpServers\" in mcpConfig)) {\n delete agentSettings.mcp_config;\n }\n\n delete agentSettings.acp_server;\n for (const key of ACP_SETTINGS_KEYS) {\n delete agentSettings[key];\n }\n\n return {\n ...agentSettings,\n llm,\n agent_context: buildAgentContext(agentSettings),\n tools: getAgentTools(agentSettings),\n };\n}\n\nfunction buildConfiguredAgentSettings(\n settings: Settings,\n): AgentSettingsPayload {\n return isAcpAgent(settings)\n ? buildConfiguredAcpAgentSettings(settings)\n : buildConfiguredOpenHandsAgentSettings(settings);\n}\n\nfunction buildConfiguredConversationSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n workingDir?: string;\n}): ConversationSettingsPayload {\n const { settings, query, conversationInstructions, plugins, workingDir } =\n options;\n const conversationSettings = toRecord(settings.conversation_settings);\n const initialMessage = buildInitialMessage(query, conversationInstructions);\n\n CONVERSATION_SETTINGS_METADATA_KEYS.forEach(\n (key) => delete conversationSettings[key],\n );\n\n const payload: ConversationSettingsPayload = {\n ...conversationSettings,\n workspace: {\n kind: \"LocalWorkspace\",\n working_dir: workingDir ?? getAgentServerWorkingDir(),\n },\n ...(initialMessage ? { initial_message: initialMessage } : {}),\n ...(plugins?.length\n ? {\n plugins: plugins.map((plugin) => ({\n source: plugin.source,\n ...(plugin.ref ? { ref: plugin.ref } : {}),\n ...(plugin.repo_path ? { repo_path: plugin.repo_path } : {}),\n })),\n }\n : {}),\n };\n\n return payload;\n}\n\ninterface LookupSecret {\n kind: \"LookupSecret\";\n url: string;\n headers?: Record<string, string>;\n description?: string;\n}\n\ntype StartConversationPayload = Record<string, unknown> & {\n agent_settings: AgentSettingsPayload;\n workspace: LocalWorkspacePayload;\n confirmation_policy: SettingsRecord;\n security_analyzer?: SettingsRecord;\n initial_message?: InitialMessagePayload;\n max_iterations: number;\n stuck_detection: true;\n autotitle: true;\n worktree: true;\n secrets_encrypted?: true;\n conversation_id?: string;\n secrets?: Record<string, LookupSecret>;\n tags?: Record<string, string>;\n tool_module_qualnames?: Record<string, string>;\n};\n\nexport interface StartConversationOptions {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n encryptedAgentSettings?: Record<string, SettingsValue>;\n encryptedConversationSettings?: Record<string, SettingsValue>;\n secretsEncrypted?: boolean;\n customSecrets?: Array<{ name: string; description?: string }>;\n}\n\nexport function buildStartConversationRequest(\n options: StartConversationOptions,\n): StartConversationPayload {\n const sourceAgentSettings = options.encryptedAgentSettings\n ? { ...options.settings, agent_settings: options.encryptedAgentSettings }\n : options.settings;\n\n const acpMode = isAcpAgent(sourceAgentSettings);\n const agentSettings = buildConfiguredAgentSettings(sourceAgentSettings);\n const acpServerTag = acpMode\n ? getAcpServerTag(sourceAgentSettings)\n : undefined;\n\n const sourceConversationOptions = options.encryptedConversationSettings\n ? {\n ...options,\n settings: {\n ...options.settings,\n conversation_settings: options.encryptedConversationSettings,\n },\n }\n : options;\n\n const conversationSettings = buildConfiguredConversationSettings(\n sourceConversationOptions,\n );\n\n const payload: StartConversationPayload = {\n agent_settings: agentSettings,\n workspace: conversationSettings.workspace,\n confirmation_policy:\n getConversationConfirmationPolicy(conversationSettings),\n max_iterations:\n typeof conversationSettings.max_iterations === \"number\"\n ? conversationSettings.max_iterations\n : 500,\n stuck_detection: true,\n autotitle: true,\n worktree: true,\n };\n\n if (acpServerTag) {\n payload.tags = { [ACP_SERVER_TAG_KEY]: acpServerTag };\n }\n\n if (options.secretsEncrypted) {\n payload.secrets_encrypted = true;\n }\n\n if (options.conversationId) {\n payload.conversation_id = options.conversationId;\n }\n\n const securityAnalyzer =\n getConversationSecurityAnalyzer(conversationSettings);\n if (securityAnalyzer) {\n payload.security_analyzer = securityAnalyzer;\n }\n\n if (conversationSettings.initial_message) {\n payload.initial_message = conversationSettings.initial_message;\n }\n\n if (conversationSettings.plugins) {\n payload.plugins = conversationSettings.plugins;\n }\n\n if (conversationSettings.hook_config) {\n payload.hook_config = conversationSettings.hook_config;\n }\n\n payload.tool_module_qualnames = {\n [CANVAS_UI_TOOL_NAME]: CANVAS_UI_TOOL_MODULE,\n ...((conversationSettings.tool_module_qualnames as\n | Record<string, string>\n | undefined) ?? {}),\n };\n\n if (conversationSettings.agent_definitions) {\n payload.agent_definitions = conversationSettings.agent_definitions;\n }\n\n if (options.customSecrets && options.customSecrets.length > 0) {\n const backend = getEffectiveLocalBackend();\n const headers = buildAuthHeaders(backend);\n\n const secrets: Record<string, LookupSecret> = {};\n for (const secret of options.customSecrets) {\n const lookupSecret: LookupSecret = {\n kind: \"LookupSecret\",\n url: `/api/settings/secrets/${encodeURIComponent(secret.name)}`,\n description: secret.description,\n };\n\n if (Object.keys(headers).length > 0) {\n lookupSecret.headers = headers;\n }\n\n secrets[secret.name] = lookupSecret;\n }\n\n payload.secrets = secrets;\n\n if (acpMode) {\n payload.agent_settings.agent_context = {\n ...payload.agent_settings.agent_context,\n secrets,\n };\n }\n }\n\n return payload;\n}\n\nexport async function buildStartConversationRequestWithEncryptedSettings(options: {\n settings: Settings;\n query?: string;\n conversationInstructions?: string;\n plugins?: PluginSpec[];\n conversationId?: string;\n workingDir?: string;\n}): Promise<Record<string, unknown>> {\n const { SecretsService } = await import(\"./secrets-service\");\n\n const [settingsResult, customSecrets] = await Promise.all([\n SettingsService.getSettingsForConversation(),\n SecretsService.getSecrets(),\n ]);\n\n const { agentSettings, conversationSettings, secretsEncrypted } =\n settingsResult;\n\n return buildStartConversationRequest({\n ...options,\n encryptedAgentSettings: agentSettings,\n encryptedConversationSettings: conversationSettings,\n secretsEncrypted,\n customSecrets,\n });\n}\n\nexport function emptyHooksResponse(): GetHooksResponse {\n return { hooks: [] };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./backend-registry/active-store.cjs`),t=require(`../node_modules/@openhands/typescript-client/dist/client/server-client.cjs`),n=require(`./agent-server-client-options.cjs`);var r=5e3,i=null,a=e=>Array.isArray(e?.usable_tools)?e.usable_tools:null,o=class extends Error{details;constructor(e){super(`Agent server not found. Could not connect to the configured agent server. Start a compatible agent server and reload the page.`),this.name=`AgentServerUnavailableError`,this.details=e??null}},s=e=>e instanceof o||typeof e==`object`&&!!e&&`name`in e&&e.name===`AgentServerUnavailableError`;function c(){i=null}function l(e){let t=a(i);return Array.isArray(t)?t.includes(e):!0}function u(e){return e instanceof Error&&e.name===`HttpError`&&`status`in e&&typeof e.status==`number`}async function d(){let a=e.getEffectiveLocalBackend(),s;try{s=await new t.ServerClient(n.getAgentServerClientOptions({host:a.host,sessionApiKey:a.apiKey||null,timeout:r})).getServerInfo()}catch(e){throw c(),u(e)?e:new o(e instanceof Error?e.message:null)}return i=s,s}exports.isAgentServerToolAvailable=l,exports.isAgentServerUnavailableError=s,exports.loadAgentServerInfo=d;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`./agent-server-config.cjs`),t=require(`./backend-registry/active-store.cjs`),n=require(`../node_modules/@openhands/typescript-client/dist/client/server-client.cjs`),r=require(`../node_modules/@openhands/typescript-client/dist/client/settings-client.cjs`),i=require(`./agent-server-client-options.cjs`);var a=5e3,o=null,s=e=>Array.isArray(e?.usable_tools)?e.usable_tools:null,c=class extends Error{details;constructor(e){super(`Agent server not found. Could not connect to the configured agent server. Start a compatible agent server and reload the page.`),this.name=`AgentServerUnavailableError`,this.details=e??null}},l=e=>e instanceof c||typeof e==`object`&&!!e&&`name`in e&&e.name===`AgentServerUnavailableError`,u=t=>e.isAuthRequired()&&m(t,401);function d(){o=null}function f(e){let t=s(o);return Array.isArray(t)?t.includes(e):!0}function p(e){return e instanceof Error&&e.name===`HttpError`&&`status`in e&&typeof e.status==`number`}function m(e,t){return p(e)&&e.status===t}async function h(){let s=t.getEffectiveLocalBackend(),l=i.getAgentServerClientOptions({host:s.host,sessionApiKey:s.apiKey||null,timeout:a}),u;try{u=await new n.ServerClient(l).getServerInfo()}catch(e){throw d(),p(e)?e:new c(e instanceof Error?e.message:null)}if(e.isAuthRequired())try{await new r.SettingsClient(l).getSettings()}catch(e){if(m(e,401))throw e;console.warn(`[agent-server] getSettings() probe failed (non-401):`,e)}return o=u,u}exports.isAgentServerAuthError=u,exports.isAgentServerToolAvailable=f,exports.isAgentServerUnavailableError=l,exports.loadAgentServerInfo=h;
2
2
  //# sourceMappingURL=agent-server-compatibility.cjs.map