@openhands/agent-canvas 1.0.0-rc.2 → 1.0.0-rc.4

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 (305) hide show
  1. package/README.md +2 -2
  2. package/README.windows.md +2 -2
  3. package/build/assets/acp-providers-C55k29rf.js +1 -0
  4. package/build/assets/{add-backend-modal-CIfhseZn.js → add-backend-modal-BdYxoUdL.js} +1 -1
  5. package/build/assets/agent-server-conversation-service.api-js3oYcdU.js +5 -0
  6. package/build/assets/{agent-settings-B6htMeS2.js → agent-settings-BNrffu3I.js} +1 -1
  7. package/build/assets/{alert-banner-D41ZKDZT.js → alert-banner-BzU93oDh.js} +1 -1
  8. package/build/assets/{analytics-consent-form-modal-TINgM_jV.js → analytics-consent-form-modal-DIfCKp6g.js} +1 -1
  9. package/build/assets/{api-key-entry-screen-Di1vHgIU.js → api-key-entry-screen-CGyS-Cna.js} +1 -1
  10. package/build/assets/{app-settings-CjCa1MOB.js → app-settings-DmOs4oik.js} +1 -1
  11. package/build/assets/{automation-detail-DPoxzTdV.js → automation-detail-DLbCVJCw.js} +1 -1
  12. package/build/assets/{automations-list-DwUEe2Ea.js → automations-list-CoYj4o97.js} +1 -1
  13. package/build/assets/{backend-form-modal-B6q897ZX.js → backend-form-modal-BUy-PzZN.js} +1 -1
  14. package/build/assets/{backend-synced-settings-badge-BwTawSCE.js → backend-synced-settings-badge-1A63yxGs.js} +1 -1
  15. package/build/assets/browser-B8bp1IqT.js +5 -0
  16. package/build/assets/{browser-tab-DiRTKik8.js → browser-tab-CiBRWB4X.js} +1 -1
  17. package/build/assets/chat-send-button-qKFZuB9E.js +1 -0
  18. package/build/assets/{circle-plus-check-toggle-B3_W6-nt.js → circle-plus-check-toggle-CboDp7XB.js} +1 -1
  19. package/build/assets/{condenser-settings-DczjwkIp.js → condenser-settings-FCBjvqSo.js} +1 -1
  20. package/build/assets/conversation-CT8AvxEH.js +1 -0
  21. package/build/assets/conversation-panel-DqDDs4WZ.js +1 -0
  22. package/build/assets/conversation-service.api-y_eB_43m.js +1 -0
  23. package/build/assets/conversation-store-CiYGBud3.js +6 -0
  24. package/build/assets/conversation-vNuLKgz6.js +19 -0
  25. package/build/assets/conversation-websocket-context-Bb4XBXoc.js +3 -0
  26. package/build/assets/{device-verify-BVl4GEvt.js → device-verify-BOQz2LJQ.js} +1 -1
  27. package/build/assets/{edit-automation-modal-kc_FzbzK.js → edit-automation-modal-C-oC5tis.js} +1 -1
  28. package/build/assets/{entry.client-CWkbusD1.js → entry.client-Db3BpFL_.js} +2 -2
  29. package/build/assets/{enum-filter-dropdown-DlY0Q3fj.js → enum-filter-dropdown-DFwoVtOw.js} +1 -1
  30. package/build/assets/{extensions-hub-NbQnt-cn.js → extensions-hub-BxZbAtjP.js} +1 -1
  31. package/build/assets/extensions-navigation-BIb-vAa2.js +1 -0
  32. package/build/assets/{files-tab-mK7Mdyuf.js → files-tab-DpulQlIo.js} +1 -1
  33. package/build/assets/{git-control-bar-branch-button-C1qmab0K.js → git-control-bar-branch-button-D1uam-nI.js} +1 -1
  34. package/build/assets/home-D77Xasws.js +1 -0
  35. package/build/assets/install-server-modal-BjmEphcZ.js +1 -0
  36. package/build/assets/{launch-BADsYeGp.js → launch-DgtB1JTX.js} +1 -1
  37. package/build/assets/llm-settings-B8kPJ0Of.js +1 -0
  38. package/build/assets/llm-settings-CjUpPsvA.js +1 -0
  39. package/build/assets/{manage-backends-modal-sH7l5NgI.js → manage-backends-modal-CTA-2x4F.js} +1 -1
  40. package/build/assets/manifest-510dd26f.js +1 -0
  41. package/build/assets/{markdown-renderer-CZq_UdmE.js → markdown-renderer-oOUs3tw5.js} +1 -1
  42. package/build/assets/{mcp-DdQ72_AO.js → mcp-CiokQDek.js} +2 -2
  43. package/build/assets/messages-BFJXB6MW.js +36 -0
  44. package/build/assets/model-selector-z_QOzaRV.js +1 -0
  45. package/build/assets/{onboarding-DCL9stdH.js → onboarding-CGUaLHfQ.js} +1 -1
  46. package/build/assets/{path-utils-CNd_jqv_.js → path-utils-0KWEiRs9.js} +1 -1
  47. package/build/assets/{planner-tab-QBnZgIXd.js → planner-tab-CNmJiZ22.js} +1 -1
  48. package/build/assets/{recommended-automations-launcher-B01jchhe.js → recommended-automations-launcher-C1_CKGHa.js} +8 -10
  49. package/build/assets/{root-BBV8Ew9E.js → root-DXsSPxni.js} +2 -2
  50. package/build/assets/root-layout-N4s3RLlj.js +2 -0
  51. package/build/assets/{sdk-section-page-BQKe3asw.js → sdk-section-page-DTyvCc52.js} +1 -1
  52. package/build/assets/{sdk-settings-schema-DoRnefvb.js → sdk-settings-schema-B0KrqqPX.js} +1 -1
  53. package/build/assets/{secrets-settings-D2EfzdpC.js → secrets-settings-BQNSDLKS.js} +1 -1
  54. package/build/assets/{settings-B7jVceyu.js → settings-BUlJrO_h.js} +1 -1
  55. package/build/assets/{settings-dropdown-input-BD7ziSoR.js → settings-dropdown-input-BUk4m23x.js} +1 -1
  56. package/build/assets/{settings-index-Xj0v9Oas.js → settings-index-DE91Eahc.js} +1 -1
  57. package/build/assets/{settings-modal-CDBy1S9S.js → settings-modal-CCaPYVqW.js} +1 -1
  58. package/build/assets/{settings-service.api-CTQ-LpAA.js → settings-service.api-4u2RKC8k.js} +1 -1
  59. package/build/assets/{settings-switch-CSHSqH99.js → settings-switch-BQiAS9ga.js} +1 -1
  60. package/build/assets/{settings-utils-BCbzc6-u.js → settings-utils-chxTa1vn.js} +1 -1
  61. package/build/assets/{shared-conversation-BHEbOdHj.js → shared-conversation-sBPLAawM.js} +1 -1
  62. package/build/assets/{sidebar-mobile-menu-toggle-YYPXGikp.js → sidebar-mobile-menu-toggle-BDXWzhyB.js} +1 -1
  63. package/build/assets/{sidebar-nav-link-CiXbBMQx.js → sidebar-nav-link-Bhlzlhp8.js} +1 -1
  64. package/build/assets/{skill-card-pill-row-BXILn-GK.js → skill-card-pill-row-Bg5joQf6.js} +1 -1
  65. package/build/assets/{skills-plugins-Bs5HiF1O.js → skills-plugins-fihjo1KZ.js} +1 -1
  66. package/build/assets/{skills-settings-CQYxMmWf.js → skills-settings-NQnuMwZP.js} +1 -1
  67. package/build/assets/{styled-tooltip-DEr7oa0m.js → styled-tooltip-GXy1qxsO.js} +1 -1
  68. package/build/assets/{task-list-tab-R9N3Wd-U.js → task-list-tab-Hl9BuVfq.js} +1 -1
  69. package/build/assets/telemetry-BoedM0mF.js +2 -0
  70. package/build/assets/{terminal-BTM3UFcQ.js → terminal-DRwe8--D.js} +1 -1
  71. package/build/assets/{use-active-conversation-BY5F6A1G.js → use-active-conversation-DJGoI9Mc.js} +1 -1
  72. package/build/assets/{use-agent-settings-schema-CsuMq16G.js → use-agent-settings-schema-DtusObuC.js} +1 -1
  73. package/build/assets/{use-agent-state-DX5NKEa_.js → use-agent-state-BXgWhFh6.js} +1 -1
  74. package/build/assets/{use-create-conversation-4iJytCT1.js → use-create-conversation-CzvaVA5A.js} +1 -1
  75. package/build/assets/use-event-store-DSpvASbC.js +1 -0
  76. package/build/assets/{use-get-secrets-BMnFFBUx.js → use-get-secrets-DiLgP147.js} +1 -1
  77. package/build/assets/use-handle-plan-click-CUZwmKIk.js +1 -0
  78. package/build/assets/{use-launch-skill-in-chat-BoqKmEHC.js → use-launch-skill-in-chat-ClRJlIx7.js} +1 -1
  79. package/build/assets/use-runtime-is-ready-CWkGQFsb.js +1 -0
  80. package/build/assets/{use-save-settings-hK6LYt0s.js → use-save-settings-CP23emUY.js} +1 -1
  81. package/build/assets/use-settings-0qFqC-r6.js +1 -0
  82. package/build/assets/{use-settings-nav-items-oZ-BlOWX.js → use-settings-nav-items-C6YxUn4h.js} +1 -1
  83. package/build/assets/{use-task-list-DydbuRFM.js → use-task-list-JPudBRv3.js} +1 -1
  84. package/build/assets/{use-tracking-DQU60djN.js → use-tracking-CjLZgh8X.js} +1 -1
  85. package/build/assets/{use-unified-vscode-url-D2Buvmxj.js → use-unified-vscode-url-DSn2tT08.js} +1 -1
  86. package/build/assets/{use-user-conversation-DwOGM1lc.js → use-user-conversation-CQ5IwnZk.js} +1 -1
  87. package/build/assets/{vendor~browser-3J6WDaAB.js → vendor~browser-Dwwc84Zf.js} +1 -1
  88. package/build/assets/{vendor~browser-tab-DYZ-OmbT.js → vendor~browser-tab-Bhohe29F.js} +1 -1
  89. package/build/assets/{vendor~files-tab-Diy4WrQz.js → vendor~files-tab-B447_Zns.js} +1 -1
  90. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CWwn0K2j.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CQQAW8hY.js} +1 -1
  91. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-dZ3D8RVL.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DFsI4CLy.js} +1 -1
  92. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BighOCzm.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DcvlNgbn.js} +1 -1
  93. package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-D13hiNGV.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-ojk_J4bB.js} +1 -1
  94. package/build/assets/{vendor~launch-D65Vw0VZ.js → vendor~launch-BdXJCmwc.js} +1 -1
  95. package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-BJPgfJoU.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DToubnIU.js} +1 -1
  96. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~jpfhx3ls-BkicN-14.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~jpfhx3ls-zdl_Rltz.js} +2 -2
  97. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~jxrvuot9-Cwz6a1DC.js → vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~jxrvuot9-BaCzvZac.js} +1 -1
  98. package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-C37jLHRk.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BwbkftxT.js} +1 -1
  99. package/build/assets/{vendor~root-layout~home~mcp~automations-list-JQ-neDIa.js → vendor~root-layout~home~mcp~automations-list-CtdIEhjQ.js} +1 -1
  100. package/build/assets/{vendor~root-layout~home~mcp~automations-list-BTTZ58Mb.js → vendor~root-layout~home~mcp~automations-list-DGOI7kQz.js} +1 -1
  101. package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-UYEKKX0Y.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-iPAfRWNQ.js} +2 -2
  102. package/build/assets/{verification-settings-Rabe5TpK.js → verification-settings-Cm02KmeI.js} +1 -1
  103. package/build/assets/{vscode-tab-zLD5Z-PP.js → vscode-tab-AF70Yke0.js} +1 -1
  104. package/build/index.html +4 -4
  105. package/build/locales/ar/openhands.json +1 -1
  106. package/build/locales/ca/openhands.json +1 -1
  107. package/build/locales/de/openhands.json +1 -1
  108. package/build/locales/en/openhands.json +1 -1
  109. package/build/locales/es/openhands.json +1 -1
  110. package/build/locales/fr/openhands.json +1 -1
  111. package/build/locales/it/openhands.json +1 -1
  112. package/build/locales/ja/openhands.json +1 -1
  113. package/build/locales/ko-KR/openhands.json +1 -1
  114. package/build/locales/no/openhands.json +1 -1
  115. package/build/locales/pt/openhands.json +1 -1
  116. package/build/locales/tr/openhands.json +1 -1
  117. package/build/locales/uk/openhands.json +1 -1
  118. package/build/locales/zh-CN/openhands.json +1 -1
  119. package/build/locales/zh-TW/openhands.json +1 -1
  120. package/config/defaults.json +2 -6
  121. package/dist/api/agent-server-adapter.cjs +3 -3
  122. package/dist/api/agent-server-adapter.cjs.map +1 -1
  123. package/dist/api/agent-server-adapter.js +90 -85
  124. package/dist/api/agent-server-adapter.js.map +1 -1
  125. package/dist/api/app-preferences-store.cjs.map +1 -1
  126. package/dist/api/app-preferences-store.d.ts +6 -2
  127. package/dist/api/app-preferences-store.js.map +1 -1
  128. package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
  129. package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
  130. package/dist/api/mcp-service/mcp-service.api.js +19 -14
  131. package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
  132. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.cjs +1 -1
  133. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.cjs.map +1 -1
  134. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.js +9 -9
  135. package/dist/components/conversation-events/chat/event-content-helpers/should-render-event.js.map +1 -1
  136. package/dist/components/conversation-events/chat/event-message.cjs +1 -1
  137. package/dist/components/conversation-events/chat/event-message.cjs.map +1 -1
  138. package/dist/components/conversation-events/chat/event-message.js +80 -71
  139. package/dist/components/conversation-events/chat/event-message.js.map +1 -1
  140. package/dist/components/features/automations/recommended-automations-launcher.d.ts +7 -1
  141. package/dist/components/features/home/workspace-selection-form.d.ts +1 -0
  142. package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
  143. package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
  144. package/dist/components/features/mcp-page/custom-server-editor.js +63 -62
  145. package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
  146. package/dist/components/features/onboarding/steps/setup-llm-step.d.ts +8 -0
  147. package/dist/components/features/sidebar/sidebar.cjs +1 -1
  148. package/dist/components/features/sidebar/sidebar.js +6 -6
  149. package/dist/components/features/skills/extensions-navigation.cjs +1 -1
  150. package/dist/components/features/skills/extensions-navigation.cjs.map +1 -1
  151. package/dist/components/features/skills/extensions-navigation.d.ts +1 -1
  152. package/dist/components/features/skills/extensions-navigation.js +27 -29
  153. package/dist/components/features/skills/extensions-navigation.js.map +1 -1
  154. package/dist/i18n/translation.cjs +1 -1
  155. package/dist/i18n/translation.cjs.map +1 -1
  156. package/dist/i18n/translation.js +15 -15
  157. package/dist/i18n/translation.js.map +1 -1
  158. package/dist/locales/ar/openhands.json +1 -1
  159. package/dist/locales/ca/openhands.json +1 -1
  160. package/dist/locales/de/openhands.json +1 -1
  161. package/dist/locales/en/openhands.json +1 -1
  162. package/dist/locales/es/openhands.json +1 -1
  163. package/dist/locales/fr/openhands.json +1 -1
  164. package/dist/locales/it/openhands.json +1 -1
  165. package/dist/locales/ja/openhands.json +1 -1
  166. package/dist/locales/ko-KR/openhands.json +1 -1
  167. package/dist/locales/no/openhands.json +1 -1
  168. package/dist/locales/pt/openhands.json +1 -1
  169. package/dist/locales/tr/openhands.json +1 -1
  170. package/dist/locales/uk/openhands.json +1 -1
  171. package/dist/locales/zh-CN/openhands.json +1 -1
  172. package/dist/locales/zh-TW/openhands.json +1 -1
  173. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs +1 -1
  174. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.cjs.map +1 -1
  175. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js +10 -1
  176. package/dist/node_modules/@openhands/typescript-client/dist/models/acp.js.map +1 -1
  177. package/dist/package.cjs +1 -1
  178. package/dist/package.cjs.map +1 -1
  179. package/dist/package.js +5 -3
  180. package/dist/package.js.map +1 -1
  181. package/dist/routes/llm-settings.cjs +1 -1
  182. package/dist/routes/llm-settings.cjs.map +1 -1
  183. package/dist/routes/llm-settings.js +21 -21
  184. package/dist/routes/llm-settings.js.map +1 -1
  185. package/dist/types/agent-server/core/events/index.d.ts +1 -0
  186. package/dist/types/agent-server/core/events/streaming-delta-event.d.ts +7 -0
  187. package/dist/types/agent-server/core/openhands-event.d.ts +2 -2
  188. package/dist/types/agent-server/type-guards.cjs +1 -1
  189. package/dist/types/agent-server/type-guards.cjs.map +1 -1
  190. package/dist/types/agent-server/type-guards.d.ts +2 -0
  191. package/dist/types/agent-server/type-guards.js +3 -3
  192. package/dist/types/agent-server/type-guards.js.map +1 -1
  193. package/dist/utils/handle-event-for-ui.cjs +1 -1
  194. package/dist/utils/handle-event-for-ui.cjs.map +1 -1
  195. package/dist/utils/handle-event-for-ui.js +69 -13
  196. package/dist/utils/handle-event-for-ui.js.map +1 -1
  197. package/dist/utils/mcp-config.cjs +1 -1
  198. package/dist/utils/mcp-config.cjs.map +1 -1
  199. package/dist/utils/mcp-config.js +27 -19
  200. package/dist/utils/mcp-config.js.map +1 -1
  201. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  202. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  203. package/dist/utils/mcp-marketplace-utils.js +38 -18
  204. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  205. package/dist/utils/normalize-display-model.cjs +1 -1
  206. package/dist/utils/normalize-display-model.cjs.map +1 -1
  207. package/dist/utils/normalize-display-model.js +8 -7
  208. package/dist/utils/normalize-display-model.js.map +1 -1
  209. package/dist/utils/openhands-llm.cjs +1 -1
  210. package/dist/utils/openhands-llm.cjs.map +1 -1
  211. package/dist/utils/openhands-llm.d.ts +13 -0
  212. package/dist/utils/openhands-llm.js +9 -3
  213. package/dist/utils/openhands-llm.js.map +1 -1
  214. package/package.json +5 -3
  215. package/scripts/check-sdk-version-sync.mjs +6 -6
  216. package/scripts/dev-safe.mjs +83 -124
  217. package/scripts/dev-with-automation.mjs +83 -5
  218. package/scripts/logger.mjs +77 -0
  219. package/scripts/runtime-services-info.mjs +199 -0
  220. package/scripts/static-server.mjs +42 -4
  221. package/build/assets/acp-providers-DZEi8wDz.js +0 -1
  222. package/build/assets/agent-server-conversation-service.api-B82pNNTm.js +0 -5
  223. package/build/assets/browser-DTei6kki.js +0 -5
  224. package/build/assets/chat-send-button-06dIuWXm.js +0 -1
  225. package/build/assets/conversation-CBlJiDaV.js +0 -19
  226. package/build/assets/conversation-Dss8XCN_.js +0 -1
  227. package/build/assets/conversation-panel-B5sVpsz5.js +0 -1
  228. package/build/assets/conversation-service.api-B4s-xIOK.js +0 -1
  229. package/build/assets/conversation-store-kHcewy1E.js +0 -1
  230. package/build/assets/conversation-websocket-context-C2yKCqvj.js +0 -3
  231. package/build/assets/extensions-navigation-oOk5yl8X.js +0 -1
  232. package/build/assets/home-ChuA06Hv.js +0 -1
  233. package/build/assets/install-server-modal--lZ1HSHB.js +0 -1
  234. package/build/assets/llm-settings-D477P0Lg.js +0 -1
  235. package/build/assets/llm-settings-DtlQ7i4C.js +0 -1
  236. package/build/assets/manifest-17af0b17.js +0 -1
  237. package/build/assets/messages-luW9zf1w.js +0 -36
  238. package/build/assets/middleware-B5rcobhi.js +0 -6
  239. package/build/assets/model-selector-DzQRgNGZ.js +0 -1
  240. package/build/assets/root-layout-pQASEqtQ.js +0 -2
  241. package/build/assets/sidebar-store-B76R2gP8.js +0 -1
  242. package/build/assets/telemetry-DCrd7gnV.js +0 -2
  243. package/build/assets/use-event-store-Rw1YbvLm.js +0 -1
  244. package/build/assets/use-handle-plan-click-DYd5a6zN.js +0 -1
  245. package/build/assets/use-runtime-is-ready-DP-KKHO6.js +0 -1
  246. package/build/assets/use-settings-Clf0Y_P3.js +0 -1
  247. /package/build/assets/{automation-LZB0MjdV.js → automation-BzmydDjr.js} +0 -0
  248. /package/build/assets/{browser-store-BjhV_9wS.js → browser-store-C5uQbbIi.js} +0 -0
  249. /package/build/assets/{checkmark-BB7QCG5T.js → checkmark-SEZPnU2I.js} +0 -0
  250. /package/build/assets/{chevron-left-small-CuuwpRi9.js → chevron-left-small-x9_-ucHG.js} +0 -0
  251. /package/build/assets/{close-Cz0OAgTy.js → close-CbOsKMRg.js} +0 -0
  252. /package/build/assets/{code-tag-Cz9AIz-X.js → code-tag-C0vR_IQH.js} +0 -0
  253. /package/build/assets/{command-store-DAd3K0d_.js → command-store-BUWgE-vZ.js} +0 -0
  254. /package/build/assets/{confirmation-modal-C_lds1Tb.js → confirmation-modal-BPgWqWRI.js} +0 -0
  255. /package/build/assets/{context-menu-list-item-DhG1Ln5m.js → context-menu-list-item-CHWCx1Mc.js} +0 -0
  256. /package/build/assets/{conversation-state-store-BUU90dVq.js → conversation-state-store-DpgQaK_O.js} +0 -0
  257. /package/build/assets/{conversation-tab-empty-state-5bW9CQke.js → conversation-tab-empty-state-Ba5hbJhn.js} +0 -0
  258. /package/build/assets/{copy-CA1Dblua.js → copy-CAxUvM-U.js} +0 -0
  259. /package/build/assets/{dist-CBUfAk0Z.js → dist-CeJSjcAI.js} +0 -0
  260. /package/build/assets/{ellipsis-button-DRRmCrWi.js → ellipsis-button-CiLx8dqc.js} +0 -0
  261. /package/build/assets/{environment-switch-overlay-BrHKX6_Z.js → environment-switch-overlay-Cow6h62p.js} +0 -0
  262. /package/build/assets/{file-DM0ihEsO.js → file-BJCSojij.js} +0 -0
  263. /package/build/assets/{files-tab-store-QlUCuW8b.js → files-tab-store-CZAEwv3x.js} +0 -0
  264. /package/build/assets/{folder-UGYUKpqb.js → folder-wShAU0y7.js} +0 -0
  265. /package/build/assets/{git-status-mapper-N4-7eaeC.js → git-status-mapper-C3rfzUex.js} +0 -0
  266. /package/build/assets/{globe-2otpEmVh.js → globe-CQ_5xwpo.js} +0 -0
  267. /package/build/assets/{handle-capture-consent-OitMkDHc.js → handle-capture-consent-DDnXMC9Y.js} +0 -0
  268. /package/build/assets/{iconBase-B_5IRYeZ.js → iconBase-1A_WRQ4E.js} +0 -0
  269. /package/build/assets/{lesson-plan-5O2tVbD1.js → lesson-plan-B607buca.js} +0 -0
  270. /package/build/assets/{link-external-kU6aFXU6.js → link-external-DCsHkAj4.js} +0 -0
  271. /package/build/assets/{map-provider-BHow6ugd.js → map-provider-XSFHmdDs.js} +0 -0
  272. /package/build/assets/{modal-close-button-BCvw9IUN.js → modal-close-button-DY-rVmld.js} +0 -0
  273. /package/build/assets/{plan-components-BRiIX8Wn.js → plan-components-DsiDjcDi.js} +0 -0
  274. /package/build/assets/{sdk-settings-field-metadata-CtO73dY6.js → sdk-settings-field-metadata-CETNItbo.js} +0 -0
  275. /package/build/assets/{search-Cbh-hHBu.js → search-BqXT2Ied.js} +0 -0
  276. /package/build/assets/{secrets-service-DEIB-Cfk.js → secrets-service-rJqZtDmI.js} +0 -0
  277. /package/build/assets/{settings-KgLvVrSm.js → settings-BgL2HUsU.js} +0 -0
  278. /package/build/assets/{settings-gear-xGs_SPgZ.js → settings-gear-DFmoMp-6.js} +0 -0
  279. /package/build/assets/{settings-input-CPr7vX81.js → settings-input-DsoZj8Dm.js} +0 -0
  280. /package/build/assets/{settings-like-page-layout-classes-GknosJgv.js → settings-like-page-layout-classes-DENKlZpD.js} +0 -0
  281. /package/build/assets/{settings-list-classes-CYDn4jUg.js → settings-list-classes-D8VAVZmi.js} +0 -0
  282. /package/build/assets/{settings-section-header-context-aD2iq1gD.js → settings-section-header-context-D61smD-W.js} +0 -0
  283. /package/build/assets/{skills-CCaEu1KQ.js → skills-BDOWVle-.js} +0 -0
  284. /package/build/assets/{switch-skeleton-C87Tx3Tc.js → switch-skeleton-QpdcdxRP.js} +0 -0
  285. /package/build/assets/{terminal-DQJ6IJUd.js → terminal-BUww3Ssl.js} +0 -0
  286. /package/build/assets/{toggle-switch-C-7juZ1u.js → toggle-switch-DDr-DnEc.js} +0 -0
  287. /package/build/assets/{typography-U1gkzkXo.js → typography-Cx7uw7z3.js} +0 -0
  288. /package/build/assets/{u-check-circle-lbkXL2z4.js → u-check-circle-CftRwky1.js} +0 -0
  289. /package/build/assets/{u-check-circle-half-CirnoxXG.js → u-check-circle-half-sGVk0BtL.js} +0 -0
  290. /package/build/assets/{u-circuit-Danff2ks.js → u-circuit-Cg9tH5qb.js} +0 -0
  291. /package/build/assets/{u-edit-CH5nNya1.js → u-edit-foF02hwH.js} +0 -0
  292. /package/build/assets/{use-breakpoint-2sN462wJ.js → use-breakpoint-Dt2knceC.js} +0 -0
  293. /package/build/assets/{use-click-outside-element-_vianyPb.js → use-click-outside-element-Bu2A3s59.js} +0 -0
  294. /package/build/assets/{use-is-authed-DrocXcet.js → use-is-authed-fNsj-Adj.js} +0 -0
  295. /package/build/assets/{use-llm-profiles-BhZRf-NX.js → use-llm-profiles-CyNVoVqm.js} +0 -0
  296. /package/build/assets/{use-skills-v8pQ02ze.js → use-skills-BWHATXK-.js} +0 -0
  297. /package/build/assets/{v4-BMWDcIWQ.js → v4-BygpdDmc.js} +0 -0
  298. /package/build/assets/{vendor~browser-C3GKF4mj.js → vendor~browser-BYEwwJqV.js} +0 -0
  299. /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-DMcFTqbt.js → vendor~conversation-panel~conversation~alert-banner-BnHToS5O.js} +0 -0
  300. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Cntsv2EN.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B4oeCCli.js} +0 -0
  301. /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DTosGXG7.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-D8cqyq4k.js} +0 -0
  302. /package/build/assets/{vendor~terminal-CnKZILnC.js → vendor~terminal-aeP3PnKf.js} +0 -0
  303. /package/build/assets/{vscode-url-helper-CwQPl6QN.js → vscode-url-helper-DOCkV_-G.js} +0 -0
  304. /package/build/assets/{waiting-for-runtime-message-B1Dzhtj5.js → waiting-for-runtime-message-Bg27u9JB.js} +0 -0
  305. /package/build/assets/{x-mark-CmcVOTk2.js → x-mark-Cn-YJVbN.js} +0 -0
@@ -6,12 +6,12 @@ import { useSettings as r } from "../hooks/query/use-settings.js";
6
6
  import { SettingsInput as i } from "../components/features/settings/settings-input.js";
7
7
  import { extractModelAndProvider as a } from "../utils/extract-model-and-provider.js";
8
8
  import { HelpLink as o } from "../ui/help-link.js";
9
- import { ModelSelector as s } from "../components/shared/modals/settings/model-selector.js";
10
- import { useAgentSettingsSchema as c } from "../hooks/query/use-agent-settings-schema.js";
11
- import { KeyStatusIcon as l } from "../components/features/settings/key-status-icon.js";
12
- import { inferInitialView as u } from "../utils/sdk-settings-schema.js";
13
- import { SdkSectionPage as d } from "../components/features/settings/sdk-settings/sdk-section-page.js";
14
- import { OPENHANDS_LLM_PROXY_BASE_URL as f, isOpenHandsProviderModel as p } from "../utils/openhands-llm.js";
9
+ import { OPENHANDS_LLM_PROXY_BASE_URL as s, isOpenHandsProxyModel as c } from "../utils/openhands-llm.js";
10
+ import { ModelSelector as l } from "../components/shared/modals/settings/model-selector.js";
11
+ import { useAgentSettingsSchema as u } from "../hooks/query/use-agent-settings-schema.js";
12
+ import { KeyStatusIcon as d } from "../components/features/settings/key-status-icon.js";
13
+ import { inferInitialView as f } from "../utils/sdk-settings-schema.js";
14
+ import { SdkSectionPage as p } from "../components/features/settings/sdk-settings/sdk-section-page.js";
15
15
  import "../components/features/settings/llm-profiles/index.js";
16
16
  import m from "react";
17
17
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
@@ -22,8 +22,8 @@ var v = new Set([
22
22
  "llm.base_url"
23
23
  ]), y = (e, t) => !e || !t ? null : `${e}/${t}`, b = (e, t) => e?.sections.flatMap((e) => e.fields).find((e) => e.key === t)?.default ?? null, x = {
24
24
  openai: new Set(["https://api.openai.com", "https://api.openai.com/v1"]),
25
- openhands: new Set([f, "https://llm-proxy.app.all-hands.dev/v1"]),
26
- litellm_proxy: new Set([f, "https://llm-proxy.app.all-hands.dev/v1"])
25
+ openhands: new Set([s, "https://llm-proxy.app.all-hands.dev/v1"]),
26
+ litellm_proxy: new Set([s, "https://llm-proxy.app.all-hands.dev/v1"])
27
27
  }, S = (e) => {
28
28
  try {
29
29
  let t = new URL(e), n = t.pathname.replace(/\/+$/, "") || "";
@@ -50,18 +50,18 @@ function w({ testId: n }) {
50
50
  });
51
51
  }
52
52
  function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S, embedded: T, hideSaveButton: E, suppressSuccessToast: D, onSaveControlChange: O }) {
53
- let { t: k } = e("openhands"), { data: A } = r(a), { data: j } = c(A?.agent_settings_schema), M = String(n.agent_settings?.llm?.model ?? ""), N = m.useCallback((e, t) => {
54
- let n = u(e, t);
53
+ let { t: k } = e("openhands"), { data: A } = r(a), { data: j } = u(A?.agent_settings_schema), M = String(n.agent_settings?.llm?.model ?? ""), N = m.useCallback((e, t) => {
54
+ let n = f(e, t);
55
55
  if (n !== "basic") return n;
56
56
  let r = e.llm_model ?? "", i = e.llm_base_url?.trim() ?? "";
57
57
  return i.length > 0 && !C(r, i) ? "all" : "basic";
58
58
  }, []);
59
- return /* @__PURE__ */ g(d, {
59
+ return /* @__PURE__ */ g(p, {
60
60
  scope: a,
61
61
  sectionKeys: ["llm"],
62
62
  excludeKeys: v,
63
63
  header: m.useCallback(({ values: e, isDisabled: n, view: r, onChange: a }) => {
64
- let c = typeof e["llm.model"] == "string" ? e["llm.model"] : "", u = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", d = c.startsWith("openhands/"), f = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", p = T ? f.length > 0 : !!A?.llm_api_key_set, m = (e, r) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(i, {
64
+ let s = typeof e["llm.model"] == "string" ? e["llm.model"] : "", c = typeof e["llm.base_url"] == "string" ? e["llm.base_url"] : "", u = s.startsWith("openhands/"), f = typeof e["llm.api_key"] == "string" ? e["llm.api_key"] : "", p = T ? f.length > 0 : !!A?.llm_api_key_set, m = (e, r) => /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(i, {
65
65
  testId: e,
66
66
  label: k(t.SETTINGS_FORM$API_KEY),
67
67
  type: "password",
@@ -70,7 +70,7 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
70
70
  placeholder: p ? "<hidden>" : "",
71
71
  onChange: (e) => a("llm.api_key", e),
72
72
  isDisabled: n,
73
- startContent: p ? /* @__PURE__ */ g(l, { isSet: p }) : void 0
73
+ startContent: p ? /* @__PURE__ */ g(d, { isSet: p }) : void 0
74
74
  }), /* @__PURE__ */ g(o, {
75
75
  testId: r,
76
76
  text: k(t.SETTINGS$DONT_KNOW_API_KEY),
@@ -83,9 +83,9 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
83
83
  className: "flex flex-col gap-6",
84
84
  "data-testid": "llm-settings-form-basic",
85
85
  children: [
86
- /* @__PURE__ */ g(s, {
87
- currentModel: c || void 0,
88
- currentBaseUrl: u || void 0,
86
+ /* @__PURE__ */ g(l, {
87
+ currentModel: s || void 0,
88
+ currentBaseUrl: c || void 0,
89
89
  onChange: (e, t) => {
90
90
  let n = y(e, t);
91
91
  n && a("llm.model", n);
@@ -93,7 +93,7 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
93
93
  wrapperClassName: "!flex-col !gap-6",
94
94
  isDisabled: n
95
95
  }),
96
- d ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help" }) : null,
96
+ u ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help" }) : null,
97
97
  m("llm-api-key-input", "llm-api-key-help-anchor")
98
98
  ]
99
99
  }) : /* @__PURE__ */ _("div", {
@@ -105,18 +105,18 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
105
105
  label: k(t.SETTINGS$CUSTOM_MODEL),
106
106
  type: "text",
107
107
  className: "w-full",
108
- value: c,
108
+ value: s,
109
109
  placeholder: M,
110
110
  onChange: (e) => a("llm.model", e),
111
111
  isDisabled: n
112
112
  }),
113
- d ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help-2" }) : null,
113
+ u ? /* @__PURE__ */ g(w, { testId: "openhands-api-key-help-2" }) : null,
114
114
  /* @__PURE__ */ g(i, {
115
115
  testId: "base-url-input",
116
116
  label: k(t.SETTINGS$BASE_URL),
117
117
  type: "text",
118
118
  className: "w-full",
119
- value: u,
119
+ value: c,
120
120
  placeholder: "https://api.openai.com",
121
121
  onChange: (e) => a("llm.base_url", e),
122
122
  isDisabled: n
@@ -133,7 +133,7 @@ function T({ scope: a = "personal", onSaveSuccess: x, initialValueOverrides: S,
133
133
  ]),
134
134
  buildPayload: m.useCallback((e, t) => {
135
135
  let n = structuredClone(e), r = n.llm ?? {};
136
- return t.view === "basic" && (r.base_url = p(r.model ?? t.values["llm.model"]) ? f : b(j, "llm.base_url"), n.llm = r), { agent_settings_diff: n };
136
+ return t.view === "basic" && (r.base_url = c(r.model ?? t.values["llm.model"], r.base_url ?? t.values["llm.base_url"]) ? s : b(j, "llm.base_url"), n.llm = r), { agent_settings_diff: n };
137
137
  }, [j]),
138
138
  getInitialView: N,
139
139
  forceShowAdvancedView: !0,
@@ -1 +1 @@
1
- {"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProviderModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n llm.base_url = isOpenHandsProviderModel(model)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"llm-settings.js","names":[],"sources":["../../src/routes/llm-settings.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ModelSelector } from \"#/components/shared/modals/settings/model-selector\";\nimport { useAgentSettingsSchema } from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { KeyStatusIcon } from \"#/components/features/settings/key-status-icon\";\nimport {\n SdkSectionHeaderProps,\n SdkSectionPage,\n SdkSectionSaveControl,\n} from \"#/components/features/settings/sdk-settings/sdk-section-page\";\nimport { LlmSettingsLocalView } from \"#/components/features/settings/llm-profiles\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n inferInitialView,\n type SettingsFormValues,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { DEFAULT_SETTINGS } from \"#/services/settings\";\nimport {\n OPENHANDS_LLM_PROXY_BASE_URL,\n isOpenHandsProxyModel,\n} from \"#/utils/openhands-llm\";\n\nconst LLM_EXCLUDED_KEYS = new Set([\"llm.model\", \"llm.api_key\", \"llm.base_url\"]);\n\nconst buildModelId = (provider: string | null, model: string | null) => {\n if (!provider || !model) return null;\n return `${provider}/${model}`;\n};\n\nconst getSchemaFieldDefaultValue = (\n schema: SettingsSchema | null | undefined,\n fieldKey: string,\n) =>\n schema?.sections\n .flatMap((section) => section.fields)\n .find((field) => field.key === fieldKey)?.default ?? null;\n\nconst KNOWN_PROVIDER_DEFAULT_BASE_URLS: Partial<Record<string, Set<string>>> = {\n openai: new Set([\"https://api.openai.com\", \"https://api.openai.com/v1\"]),\n openhands: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n litellm_proxy: new Set([\n OPENHANDS_LLM_PROXY_BASE_URL,\n \"https://llm-proxy.app.all-hands.dev/v1\",\n ]),\n};\n\nconst normalizeBaseUrl = (baseUrl: string) => {\n try {\n const parsedUrl = new URL(baseUrl);\n const normalizedPath = parsedUrl.pathname.replace(/\\/+$/, \"\") || \"\";\n return `${parsedUrl.origin}${normalizedPath}`;\n } catch {\n return baseUrl.trim().replace(/\\/+$/, \"\");\n }\n};\n\nconst isProviderDefaultBaseUrl = (model: string, baseUrl: string) => {\n const normalizedBaseUrl = normalizeBaseUrl(baseUrl);\n const { provider } = extractModelAndProvider(model);\n\n if (provider) {\n const knownDefaults = KNOWN_PROVIDER_DEFAULT_BASE_URLS[provider];\n if (knownDefaults) {\n return knownDefaults.has(normalizedBaseUrl);\n }\n }\n\n return Object.values(KNOWN_PROVIDER_DEFAULT_BASE_URLS).some((knownDefaults) =>\n knownDefaults?.has(normalizedBaseUrl),\n );\n};\n\ninterface OpenHandsApiKeyHelpProps {\n testId: string;\n}\n\nfunction OpenHandsApiKeyHelp({ testId }: OpenHandsApiKeyHelpProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <HelpLink\n testId={testId}\n text={t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_TEXT)}\n linkText={t(I18nKey.SETTINGS$NAV_API_KEYS)}\n href=\"https://app.all-hands.dev/settings/api-keys\"\n suffix={` ${t(I18nKey.SETTINGS$OPENHANDS_API_KEY_HELP_SUFFIX)}`}\n />\n );\n}\n\nexport function LlmSettingsScreen({\n scope = \"personal\",\n onSaveSuccess,\n initialValueOverrides,\n embedded,\n hideSaveButton,\n suppressSuccessToast,\n onSaveControlChange,\n}: {\n scope?: SettingsScope;\n /** Optional hook fired after a successful save (e.g. advance an onboarding step). */\n onSaveSuccess?: () => void;\n /** Forwarded to {@link SdkSectionPage}. */\n initialValueOverrides?: SettingsFormValues;\n /** Forwarded to {@link SdkSectionPage}. */\n embedded?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n hideSaveButton?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n suppressSuccessToast?: boolean;\n /** Forwarded to {@link SdkSectionPage}. */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n}) {\n const { t } = useTranslation(\"openhands\");\n\n const { data: settings } = useSettings(scope);\n const { data: schema } = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n\n const defaultModel = String(\n (DEFAULT_SETTINGS.agent_settings?.llm as Record<string, unknown>)?.model ??\n \"\",\n );\n\n const getInitialView = React.useCallback(\n (\n currentSettings: Settings,\n filteredSchema: SettingsSchema,\n ): SettingsView => {\n const schemaView = inferInitialView(currentSettings, filteredSchema);\n if (schemaView !== \"basic\") {\n return schemaView;\n }\n\n const currentModel = currentSettings.llm_model ?? \"\";\n const trimmedBaseUrl = currentSettings.llm_base_url?.trim() ?? \"\";\n const hasCustomBaseUrl =\n trimmedBaseUrl.length > 0 &&\n !isProviderDefaultBaseUrl(currentModel, trimmedBaseUrl);\n\n return hasCustomBaseUrl ? \"all\" : \"basic\";\n },\n [],\n );\n\n const buildHeader = React.useCallback(\n ({ values, isDisabled, view, onChange }: SdkSectionHeaderProps) => {\n const modelValue =\n typeof values[\"llm.model\"] === \"string\" ? values[\"llm.model\"] : \"\";\n const baseUrlValue =\n typeof values[\"llm.base_url\"] === \"string\"\n ? values[\"llm.base_url\"]\n : \"\";\n const showOpenHandsApiKeyHelp = modelValue.startsWith(\"openhands/\");\n\n const apiKeyValue =\n typeof values[\"llm.api_key\"] === \"string\" ? values[\"llm.api_key\"] : \"\";\n // For embedded profile forms (create/edit) the global\n // `llm_api_key_set` flag is misleading: a brand-new profile would show a\n // \"key set\" indicator just because some other profile has a key. Reflect\n // the form's own key state instead so create mode starts visibly unset.\n const apiKeyIsSet = embedded\n ? apiKeyValue.length > 0\n : Boolean(settings?.llm_api_key_set);\n\n const renderApiKeyInput = (testId: string, helpTestId: string) => (\n <>\n <SettingsInput\n testId={testId}\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n value={apiKeyValue}\n placeholder={apiKeyIsSet ? \"<hidden>\" : \"\"}\n onChange={(value) => onChange(\"llm.api_key\", value)}\n isDisabled={isDisabled}\n startContent={\n apiKeyIsSet ? <KeyStatusIcon isSet={apiKeyIsSet} /> : undefined\n }\n />\n\n <HelpLink\n testId={helpTestId}\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n />\n </>\n );\n\n return (\n <div className=\"flex flex-col gap-6\">\n {view === \"basic\" ? (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-basic\"\n >\n <ModelSelector\n currentModel={modelValue || undefined}\n currentBaseUrl={baseUrlValue || undefined}\n onChange={(provider, model) => {\n const nextModel = buildModelId(provider, model);\n if (nextModel) {\n onChange(\"llm.model\", nextModel);\n }\n }}\n wrapperClassName=\"!flex-col !gap-6\"\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help\" />\n ) : null}\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor\",\n )}\n </div>\n ) : (\n <div\n className=\"flex flex-col gap-6\"\n data-testid=\"llm-settings-form-advanced\"\n >\n <SettingsInput\n testId=\"llm-custom-model-input\"\n label={t(I18nKey.SETTINGS$CUSTOM_MODEL)}\n type=\"text\"\n className=\"w-full\"\n value={modelValue}\n placeholder={defaultModel}\n onChange={(value) => onChange(\"llm.model\", value)}\n isDisabled={isDisabled}\n />\n\n {showOpenHandsApiKeyHelp ? (\n <OpenHandsApiKeyHelp testId=\"openhands-api-key-help-2\" />\n ) : null}\n\n <SettingsInput\n testId=\"base-url-input\"\n label={t(I18nKey.SETTINGS$BASE_URL)}\n type=\"text\"\n className=\"w-full\"\n value={baseUrlValue}\n placeholder=\"https://api.openai.com\"\n onChange={(value) => onChange(\"llm.base_url\", value)}\n isDisabled={isDisabled}\n />\n\n {renderApiKeyInput(\n \"llm-api-key-input\",\n \"llm-api-key-help-anchor-advanced\",\n )}\n </div>\n )}\n </div>\n );\n },\n [defaultModel, embedded, settings?.llm_api_key_set, t],\n );\n\n const buildPayload = React.useCallback(\n (\n basePayload: Record<string, unknown>,\n context: {\n values: Record<string, string | boolean>;\n view: SettingsView;\n },\n ) => {\n // basePayload is a nested dict (e.g. {llm: {model: \"gpt-4\"}})\n const agentSettings = structuredClone(basePayload);\n\n const llm = (agentSettings.llm ?? {}) as Record<string, unknown>;\n\n if (context.view === \"basic\") {\n const model = llm.model ?? context.values[\"llm.model\"];\n const baseUrl = llm.base_url ?? context.values[\"llm.base_url\"];\n llm.base_url = isOpenHandsProxyModel(model, baseUrl)\n ? OPENHANDS_LLM_PROXY_BASE_URL\n : getSchemaFieldDefaultValue(schema, \"llm.base_url\");\n agentSettings.llm = llm;\n }\n\n return { agent_settings_diff: agentSettings };\n },\n [schema],\n );\n\n return (\n <SdkSectionPage\n scope={scope}\n sectionKeys={[\"llm\"]}\n excludeKeys={LLM_EXCLUDED_KEYS}\n header={buildHeader}\n buildPayload={buildPayload}\n getInitialView={getInitialView}\n forceShowAdvancedView\n allowAllView\n onSaveSuccess={onSaveSuccess}\n initialValueOverrides={initialValueOverrides}\n embedded={embedded}\n hideSaveButton={hideSaveButton}\n suppressSuccessToast={suppressSuccessToast}\n onSaveControlChange={onSaveControlChange}\n testId=\"llm-settings-screen\"\n />\n );\n}\n\n/**\n * Default export for the route renders different views based on backend type:\n * - Local backends: LlmSettingsLocalView with profile management\n * - Cloud backends: Standard LlmSettingsScreen (profiles are not supported)\n *\n * The LlmSettingsScreen component is also exported for embedded use cases\n * (e.g., onboarding, profile editing forms).\n *\n * Note: This is a route file, only the router should import the default export.\n * Other consumers should use the named export `LlmSettingsScreen` for embedded\n * use cases.\n */\nexport default function LlmSettingsRoute() {\n const { backend } = useActiveBackend();\n const isCloud = backend.kind === \"cloud\";\n\n // Cloud backends use the standard LLM settings form (no profiles support)\n if (isCloud) {\n return <LlmSettingsScreen />;\n }\n\n // Local backends use the profile management view\n return <LlmSettingsLocalView />;\n}\n"],"mappings":"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"}
@@ -6,4 +6,5 @@ export * from "./hook-execution-event";
6
6
  export * from "./message-event";
7
7
  export * from "./observation-event";
8
8
  export * from "./pause-event";
9
+ export * from "./streaming-delta-event";
9
10
  export * from "./system-event";
@@ -0,0 +1,7 @@
1
+ import { BaseEvent } from "../base/event";
2
+ export interface StreamingDeltaEvent extends BaseEvent {
3
+ kind: "StreamingDeltaEvent";
4
+ source: "agent";
5
+ content: string | null;
6
+ reasoning_content: string | null;
7
+ }
@@ -1,6 +1,6 @@
1
- import { ACPToolCallEvent, ActionEvent, MessageEvent, ObservationEvent, UserRejectObservation, AgentErrorEvent, SystemPromptEvent, CondensationEvent, CondensationRequestEvent, CondensationSummaryEvent, ConversationStateUpdateEvent, ConversationErrorEvent, HookExecutionEvent, PauseEvent, ServerErrorEvent } from "./events/index";
1
+ import { ACPToolCallEvent, ActionEvent, MessageEvent, ObservationEvent, UserRejectObservation, AgentErrorEvent, SystemPromptEvent, CondensationEvent, CondensationRequestEvent, CondensationSummaryEvent, ConversationStateUpdateEvent, ConversationErrorEvent, HookExecutionEvent, PauseEvent, ServerErrorEvent, StreamingDeltaEvent } from "./events/index";
2
2
  /**
3
3
  * Union type representing all possible OpenHands events.
4
4
  * This includes all main event types that can occur in the system.
5
5
  */
6
- export type OpenHandsEvent = ActionEvent | MessageEvent | ObservationEvent | UserRejectObservation | AgentErrorEvent | SystemPromptEvent | ACPToolCallEvent | HookExecutionEvent | CondensationEvent | CondensationRequestEvent | CondensationSummaryEvent | ConversationStateUpdateEvent | ConversationErrorEvent | PauseEvent | ServerErrorEvent;
6
+ export type OpenHandsEvent = ActionEvent | MessageEvent | ObservationEvent | UserRejectObservation | AgentErrorEvent | SystemPromptEvent | ACPToolCallEvent | HookExecutionEvent | CondensationEvent | CondensationRequestEvent | CondensationSummaryEvent | ConversationStateUpdateEvent | ConversationErrorEvent | PauseEvent | ServerErrorEvent | StreamingDeltaEvent;
@@ -1,2 +1,2 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);function e(e){return typeof e==`object`&&!!e&&`id`in e&&`timestamp`in e&&`source`in e&&typeof e.id==`string`&&e.id.length>0&&typeof e.timestamp==`string`&&e.timestamp.length>0&&typeof e.source==`string`&&(e.source===`agent`||e.source===`user`||e.source===`environment`||e.source===`hook`)}var t=e=>e.source===`environment`&&`action_id`in e&&`observation`in e&&e.observation!==null&&typeof e.observation==`object`&&`kind`in e.observation,n=e=>e.source===`agent`&&`tool_name`in e&&`tool_call_id`in e&&`error`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`&&typeof e.error==`string`,r=e=>`llm_message`in e&&typeof e.llm_message==`object`&&e.llm_message!==null&&`role`in e.llm_message&&`content`in e.llm_message,i=e=>r(e)&&e.llm_message.role===`user`,a=e=>e.source===`agent`&&`action`in e&&e.action!==null&&typeof e.action==`object`&&`kind`in e.action&&`tool_name`in e&&`tool_call_id`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`,o=e=>a(e)&&(e.action.kind===`ExecuteBashAction`||e.action.kind===`TerminalAction`),s=e=>t(e)&&(e.observation.kind===`ExecuteBashObservation`||e.observation.kind===`TerminalObservation`),c=e=>t(e)&&e.observation.kind===`PlanningFileEditorObservation`,l=e=>t(e)&&e.observation.kind===`BrowserObservation`,u=e=>t(e)&&e.observation.kind===`SwitchLLMObservation`,d=e=>a(e)&&e.action.kind===`BrowserNavigateAction`,f=e=>a(e)&&e.tool_name===`canvas_ui`,p=e=>e.source===`agent`&&`system_prompt`in e&&`tools`in e&&typeof e.system_prompt==`object`&&Array.isArray(e.tools),m=e=>`kind`in e&&e.kind===`ConversationStateUpdateEvent`,h=e=>e.key===`full_state`,g=e=>e.key===`execution_status`,_=e=>e.key===`stats`,v=e=>`kind`in e&&e.kind===`ConversationErrorEvent`,y=e=>`kind`in e&&e.kind===`ServerErrorEvent`,b=e=>v(e)||y(e),x=e=>`kind`in e&&e.kind===`HookExecutionEvent`,S=e=>`kind`in e&&e.kind===`ACPToolCallEvent`;function C(t){return e(t)}exports.isACPToolCallEvent=S,exports.isActionEvent=a,exports.isAgentErrorEvent=n,exports.isAgentServerEvent=C,exports.isAgentStatusConversationStateUpdateEvent=g,exports.isBrowserNavigateActionEvent=d,exports.isBrowserObservationEvent=l,exports.isCanvasUIActionEvent=f,exports.isConversationStateUpdateEvent=m,exports.isDisplayableErrorEvent=b,exports.isExecuteBashActionEvent=o,exports.isExecuteBashObservationEvent=s,exports.isFullStateConversationStateUpdateEvent=h,exports.isHookExecutionEvent=x,exports.isMessageEvent=r,exports.isObservationEvent=t,exports.isPlanningFileEditorObservationEvent=c,exports.isStatsConversationStateUpdateEvent=_,exports.isSwitchLLMObservationEvent=u,exports.isSystemPromptEvent=p,exports.isUserMessageEvent=i;
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);function e(e){return typeof e==`object`&&!!e&&`id`in e&&`timestamp`in e&&`source`in e&&typeof e.id==`string`&&e.id.length>0&&typeof e.timestamp==`string`&&e.timestamp.length>0&&typeof e.source==`string`&&(e.source===`agent`||e.source===`user`||e.source===`environment`||e.source===`hook`)}var t=e=>e.source===`environment`&&`action_id`in e&&`observation`in e&&e.observation!==null&&typeof e.observation==`object`&&`kind`in e.observation,n=e=>e.source===`agent`&&`tool_name`in e&&`tool_call_id`in e&&`error`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`&&typeof e.error==`string`,r=e=>`llm_message`in e&&typeof e.llm_message==`object`&&e.llm_message!==null&&`role`in e.llm_message&&`content`in e.llm_message,i=e=>r(e)&&e.llm_message.role===`user`,a=e=>e.source===`agent`&&`action`in e&&e.action!==null&&typeof e.action==`object`&&`kind`in e.action&&`tool_name`in e&&`tool_call_id`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`,o=e=>a(e)&&(e.action.kind===`ExecuteBashAction`||e.action.kind===`TerminalAction`),s=e=>t(e)&&(e.observation.kind===`ExecuteBashObservation`||e.observation.kind===`TerminalObservation`),c=e=>t(e)&&e.observation.kind===`PlanningFileEditorObservation`,l=e=>t(e)&&e.observation.kind===`BrowserObservation`,u=e=>t(e)&&e.observation.kind===`SwitchLLMObservation`,d=e=>a(e)&&e.action.kind===`BrowserNavigateAction`,f=e=>a(e)&&e.tool_name===`canvas_ui`,p=e=>e.source===`agent`&&`system_prompt`in e&&`tools`in e&&typeof e.system_prompt==`object`&&Array.isArray(e.tools),m=e=>`kind`in e&&e.kind===`ConversationStateUpdateEvent`,h=e=>e.key===`full_state`,g=e=>e.key===`execution_status`,_=e=>e.key===`stats`,v=e=>`kind`in e&&e.kind===`ConversationErrorEvent`,y=e=>`kind`in e&&e.kind===`ServerErrorEvent`,b=e=>v(e)||y(e),x=e=>`kind`in e&&e.kind===`HookExecutionEvent`,S=e=>`kind`in e&&e.kind===`ACPToolCallEvent`,C=e=>`kind`in e&&e.kind===`StreamingDeltaEvent`;function w(t){return e(t)}exports.isACPToolCallEvent=S,exports.isActionEvent=a,exports.isAgentErrorEvent=n,exports.isAgentServerEvent=w,exports.isAgentStatusConversationStateUpdateEvent=g,exports.isBrowserNavigateActionEvent=d,exports.isBrowserObservationEvent=l,exports.isCanvasUIActionEvent=f,exports.isConversationStateUpdateEvent=m,exports.isDisplayableErrorEvent=b,exports.isExecuteBashActionEvent=o,exports.isExecuteBashObservationEvent=s,exports.isFullStateConversationStateUpdateEvent=h,exports.isHookExecutionEvent=x,exports.isMessageEvent=r,exports.isObservationEvent=t,exports.isPlanningFileEditorObservationEvent=c,exports.isStatsConversationStateUpdateEvent=_,exports.isStreamingDeltaEvent=C,exports.isSwitchLLMObservationEvent=u,exports.isSystemPromptEvent=p,exports.isUserMessageEvent=i;
2
2
  //# sourceMappingURL=type-guards.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"type-guards.cjs","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for the canvas_ui custom tool's ActionEvent.\n *\n * The tool is injected via tool_module_qualnames (see canvas_ui_tool.py and\n * agent-server-adapter.ts). We discriminate on tool_name (which we control\n * via register_tool(\"canvas_ui\", ...)). The predicate narrows the event so\n * the call site can read `event.action.command` etc. without further casts.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) && event.tool_name === \"canvas_ui\";\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":"gDAkCA,SAAgB,EAAY,EAAoC,CAC9D,OAEE,OAAO,GAAU,YADjB,GAEA,OAAQ,GACR,cAAe,GACf,WAAY,GACZ,OAAO,EAAM,IAAO,UACpB,EAAM,GAAG,OAAS,GAClB,OAAO,EAAM,WAAc,UAC3B,EAAM,UAAU,OAAS,GACzB,OAAO,EAAM,QAAW,WACvB,EAAM,SAAW,SAChB,EAAM,SAAW,QACjB,EAAM,SAAW,eACjB,EAAM,SAAW,QAOvB,IAAa,EACX,GAEA,EAAM,SAAW,eACjB,cAAe,GACf,gBAAiB,GACjB,EAAM,cAAgB,MACtB,OAAO,EAAM,aAAgB,UAC7B,SAAU,EAAM,YAKL,EACX,GAEA,EAAM,SAAW,SACjB,cAAe,GACf,iBAAkB,GAClB,UAAW,GACX,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,UAC9B,OAAO,EAAM,OAAU,SAKZ,EAAkB,GAC7B,gBAAiB,GACjB,OAAO,EAAM,aAAgB,UAC7B,EAAM,cAAgB,MACtB,SAAU,EAAM,aAChB,YAAa,EAAM,YAKR,EACX,GAEA,EAAe,EAAM,EAAI,EAAM,YAAY,OAAS,OAKzC,EAAiB,GAC5B,EAAM,SAAW,SACjB,WAAY,GACZ,EAAM,SAAW,MACjB,OAAO,EAAM,QAAW,UACxB,SAAU,EAAM,QAChB,cAAe,GACf,iBAAkB,GAClB,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,SAKnB,EACX,GAEA,EAAc,EAAM,GACnB,EAAM,OAAO,OAAS,qBACrB,EAAM,OAAO,OAAS,kBAKb,EACX,GAEA,EAAmB,EAAM,GACxB,EAAM,YAAY,OAAS,0BAC1B,EAAM,YAAY,OAAS,uBAKlB,EACX,GAEA,EAAmB,EAAM,EACzB,EAAM,YAAY,OAAS,gCAKhB,EACX,GAEA,EAAmB,EAAM,EAAI,EAAM,YAAY,OAAS,qBAK7C,EACX,GAEA,EAAmB,EAAM,EACzB,EAAM,YAAY,OAAS,uBAKhB,EACX,GAEA,EAAc,EAAM,EAAI,EAAM,OAAO,OAAS,wBAUnC,EACX,GAEA,EAAc,EAAM,EAAI,EAAM,YAAc,YAKjC,EACX,GAEA,EAAM,SAAW,SACjB,kBAAmB,GACnB,UAAW,GACX,OAAO,EAAM,eAAkB,UAC/B,MAAM,QAAQ,EAAM,MAAM,CAKf,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,+BAEvB,EACX,GACmD,EAAM,MAAQ,aAEtD,EACX,GAEA,EAAM,MAAQ,mBAEH,EACX,GAC+C,EAAM,MAAQ,QAKlD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,yBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAMvB,EAA2B,GACtC,EAAyB,EAAM,EAAI,EAAmB,EAAM,CAKjD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,qBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAUpC,SAAgB,EAAmB,EAAyC,CAC1E,OAAO,EAAY,EAAM"}
1
+ {"version":3,"file":"type-guards.cjs","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { StreamingDeltaEvent } from \"./core/events/streaming-delta-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for the canvas_ui custom tool's ActionEvent.\n *\n * The tool is injected via tool_module_qualnames (see canvas_ui_tool.py and\n * agent-server-adapter.ts). We discriminate on tool_name (which we control\n * via register_tool(\"canvas_ui\", ...)). The predicate narrows the event so\n * the call site can read `event.action.command` etc. without further casts.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) && event.tool_name === \"canvas_ui\";\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\nexport const isStreamingDeltaEvent = (\n event: OpenHandsEvent,\n): event is StreamingDeltaEvent =>\n \"kind\" in event && event.kind === \"StreamingDeltaEvent\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":"gDAmCA,SAAgB,EAAY,EAAoC,CAC9D,OAEE,OAAO,GAAU,YADjB,GAEA,OAAQ,GACR,cAAe,GACf,WAAY,GACZ,OAAO,EAAM,IAAO,UACpB,EAAM,GAAG,OAAS,GAClB,OAAO,EAAM,WAAc,UAC3B,EAAM,UAAU,OAAS,GACzB,OAAO,EAAM,QAAW,WACvB,EAAM,SAAW,SAChB,EAAM,SAAW,QACjB,EAAM,SAAW,eACjB,EAAM,SAAW,QAOvB,IAAa,EACX,GAEA,EAAM,SAAW,eACjB,cAAe,GACf,gBAAiB,GACjB,EAAM,cAAgB,MACtB,OAAO,EAAM,aAAgB,UAC7B,SAAU,EAAM,YAKL,EACX,GAEA,EAAM,SAAW,SACjB,cAAe,GACf,iBAAkB,GAClB,UAAW,GACX,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,UAC9B,OAAO,EAAM,OAAU,SAKZ,EAAkB,GAC7B,gBAAiB,GACjB,OAAO,EAAM,aAAgB,UAC7B,EAAM,cAAgB,MACtB,SAAU,EAAM,aAChB,YAAa,EAAM,YAKR,EACX,GAEA,EAAe,EAAM,EAAI,EAAM,YAAY,OAAS,OAKzC,EAAiB,GAC5B,EAAM,SAAW,SACjB,WAAY,GACZ,EAAM,SAAW,MACjB,OAAO,EAAM,QAAW,UACxB,SAAU,EAAM,QAChB,cAAe,GACf,iBAAkB,GAClB,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,SAKnB,EACX,GAEA,EAAc,EAAM,GACnB,EAAM,OAAO,OAAS,qBACrB,EAAM,OAAO,OAAS,kBAKb,EACX,GAEA,EAAmB,EAAM,GACxB,EAAM,YAAY,OAAS,0BAC1B,EAAM,YAAY,OAAS,uBAKlB,EACX,GAEA,EAAmB,EAAM,EACzB,EAAM,YAAY,OAAS,gCAKhB,EACX,GAEA,EAAmB,EAAM,EAAI,EAAM,YAAY,OAAS,qBAK7C,EACX,GAEA,EAAmB,EAAM,EACzB,EAAM,YAAY,OAAS,uBAKhB,EACX,GAEA,EAAc,EAAM,EAAI,EAAM,OAAO,OAAS,wBAUnC,EACX,GAEA,EAAc,EAAM,EAAI,EAAM,YAAc,YAKjC,EACX,GAEA,EAAM,SAAW,SACjB,kBAAmB,GACnB,UAAW,GACX,OAAO,EAAM,eAAkB,UAC/B,MAAM,QAAQ,EAAM,MAAM,CAKf,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,+BAEvB,EACX,GACmD,EAAM,MAAQ,aAEtD,EACX,GAEA,EAAM,MAAQ,mBAEH,EACX,GAC+C,EAAM,MAAQ,QAKlD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,yBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAMvB,EAA2B,GACtC,EAAyB,EAAM,EAAI,EAAmB,EAAM,CAKjD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,qBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAEvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,sBAUpC,SAAgB,EAAmB,EAAyC,CAC1E,OAAO,EAAY,EAAM"}
@@ -5,6 +5,7 @@ import { ActionEvent } from "./core/events/action-event";
5
5
  import { ConversationStateUpdateEvent, ConversationStateUpdateEventAgentStatus, ConversationStateUpdateEventFullState, ConversationStateUpdateEventStats, ConversationErrorEvent, ServerErrorEvent } from "./core/events/conversation-state-event";
6
6
  import { HookExecutionEvent } from "./core/events/hook-execution-event";
7
7
  import { ACPToolCallEvent } from "./core/events/acp-tool-call-event";
8
+ import { StreamingDeltaEvent } from "./core/events/streaming-delta-event";
8
9
  import { SystemPromptEvent } from "./core/events/system-event";
9
10
  /**
10
11
  * Type guard to check if an unknown value is a valid BaseEvent
@@ -97,6 +98,7 @@ export declare const isHookExecutionEvent: (event: OpenHandsEvent) => event is H
97
98
  * Type guard function to check if an event is an ACP tool call event
98
99
  */
99
100
  export declare const isACPToolCallEvent: (event: OpenHandsEvent) => event is ACPToolCallEvent;
101
+ export declare const isStreamingDeltaEvent: (event: OpenHandsEvent) => event is StreamingDeltaEvent;
100
102
  /**
101
103
  * Type guard to check if an event is an agent-server OpenHandsEvent.
102
104
  * Uses isBaseEvent to validate the complete event structure.
@@ -2,11 +2,11 @@
2
2
  function e(e) {
3
3
  return typeof e == "object" && !!e && "id" in e && "timestamp" in e && "source" in e && typeof e.id == "string" && e.id.length > 0 && typeof e.timestamp == "string" && e.timestamp.length > 0 && typeof e.source == "string" && (e.source === "agent" || e.source === "user" || e.source === "environment" || e.source === "hook");
4
4
  }
5
- var t = (e) => e.source === "environment" && "action_id" in e && "observation" in e && e.observation !== null && typeof e.observation == "object" && "kind" in e.observation, n = (e) => e.source === "agent" && "tool_name" in e && "tool_call_id" in e && "error" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string" && typeof e.error == "string", r = (e) => "llm_message" in e && typeof e.llm_message == "object" && e.llm_message !== null && "role" in e.llm_message && "content" in e.llm_message, i = (e) => r(e) && e.llm_message.role === "user", a = (e) => e.source === "agent" && "action" in e && e.action !== null && typeof e.action == "object" && "kind" in e.action && "tool_name" in e && "tool_call_id" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string", o = (e) => a(e) && (e.action.kind === "ExecuteBashAction" || e.action.kind === "TerminalAction"), s = (e) => t(e) && (e.observation.kind === "ExecuteBashObservation" || e.observation.kind === "TerminalObservation"), c = (e) => t(e) && e.observation.kind === "PlanningFileEditorObservation", l = (e) => t(e) && e.observation.kind === "BrowserObservation", u = (e) => t(e) && e.observation.kind === "SwitchLLMObservation", d = (e) => a(e) && e.action.kind === "BrowserNavigateAction", f = (e) => a(e) && e.tool_name === "canvas_ui", p = (e) => e.source === "agent" && "system_prompt" in e && "tools" in e && typeof e.system_prompt == "object" && Array.isArray(e.tools), m = (e) => "kind" in e && e.kind === "ConversationStateUpdateEvent", h = (e) => e.key === "full_state", g = (e) => e.key === "execution_status", _ = (e) => e.key === "stats", v = (e) => "kind" in e && e.kind === "ConversationErrorEvent", y = (e) => "kind" in e && e.kind === "ServerErrorEvent", b = (e) => v(e) || y(e), x = (e) => "kind" in e && e.kind === "HookExecutionEvent", S = (e) => "kind" in e && e.kind === "ACPToolCallEvent";
6
- function C(t) {
5
+ var t = (e) => e.source === "environment" && "action_id" in e && "observation" in e && e.observation !== null && typeof e.observation == "object" && "kind" in e.observation, n = (e) => e.source === "agent" && "tool_name" in e && "tool_call_id" in e && "error" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string" && typeof e.error == "string", r = (e) => "llm_message" in e && typeof e.llm_message == "object" && e.llm_message !== null && "role" in e.llm_message && "content" in e.llm_message, i = (e) => r(e) && e.llm_message.role === "user", a = (e) => e.source === "agent" && "action" in e && e.action !== null && typeof e.action == "object" && "kind" in e.action && "tool_name" in e && "tool_call_id" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string", o = (e) => a(e) && (e.action.kind === "ExecuteBashAction" || e.action.kind === "TerminalAction"), s = (e) => t(e) && (e.observation.kind === "ExecuteBashObservation" || e.observation.kind === "TerminalObservation"), c = (e) => t(e) && e.observation.kind === "PlanningFileEditorObservation", l = (e) => t(e) && e.observation.kind === "BrowserObservation", u = (e) => t(e) && e.observation.kind === "SwitchLLMObservation", d = (e) => a(e) && e.action.kind === "BrowserNavigateAction", f = (e) => a(e) && e.tool_name === "canvas_ui", p = (e) => e.source === "agent" && "system_prompt" in e && "tools" in e && typeof e.system_prompt == "object" && Array.isArray(e.tools), m = (e) => "kind" in e && e.kind === "ConversationStateUpdateEvent", h = (e) => e.key === "full_state", g = (e) => e.key === "execution_status", _ = (e) => e.key === "stats", v = (e) => "kind" in e && e.kind === "ConversationErrorEvent", y = (e) => "kind" in e && e.kind === "ServerErrorEvent", b = (e) => v(e) || y(e), x = (e) => "kind" in e && e.kind === "HookExecutionEvent", S = (e) => "kind" in e && e.kind === "ACPToolCallEvent", C = (e) => "kind" in e && e.kind === "StreamingDeltaEvent";
6
+ function w(t) {
7
7
  return e(t);
8
8
  }
9
9
  //#endregion
10
- export { S as isACPToolCallEvent, a as isActionEvent, n as isAgentErrorEvent, C as isAgentServerEvent, g as isAgentStatusConversationStateUpdateEvent, d as isBrowserNavigateActionEvent, l as isBrowserObservationEvent, f as isCanvasUIActionEvent, m as isConversationStateUpdateEvent, b as isDisplayableErrorEvent, o as isExecuteBashActionEvent, s as isExecuteBashObservationEvent, h as isFullStateConversationStateUpdateEvent, x as isHookExecutionEvent, r as isMessageEvent, t as isObservationEvent, c as isPlanningFileEditorObservationEvent, _ as isStatsConversationStateUpdateEvent, u as isSwitchLLMObservationEvent, p as isSystemPromptEvent, i as isUserMessageEvent };
10
+ export { S as isACPToolCallEvent, a as isActionEvent, n as isAgentErrorEvent, w as isAgentServerEvent, g as isAgentStatusConversationStateUpdateEvent, d as isBrowserNavigateActionEvent, l as isBrowserObservationEvent, f as isCanvasUIActionEvent, m as isConversationStateUpdateEvent, b as isDisplayableErrorEvent, o as isExecuteBashActionEvent, s as isExecuteBashObservationEvent, h as isFullStateConversationStateUpdateEvent, x as isHookExecutionEvent, r as isMessageEvent, t as isObservationEvent, c as isPlanningFileEditorObservationEvent, _ as isStatsConversationStateUpdateEvent, C as isStreamingDeltaEvent, u as isSwitchLLMObservationEvent, p as isSystemPromptEvent, i as isUserMessageEvent };
11
11
 
12
12
  //# sourceMappingURL=type-guards.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"type-guards.js","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for the canvas_ui custom tool's ActionEvent.\n *\n * The tool is injected via tool_module_qualnames (see canvas_ui_tool.py and\n * agent-server-adapter.ts). We discriminate on tool_name (which we control\n * via register_tool(\"canvas_ui\", ...)). The predicate narrows the event so\n * the call site can read `event.action.command` etc. without further casts.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) && event.tool_name === \"canvas_ui\";\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":";AAkCA,SAAgB,EAAY,GAAoC;AAC9D,QAEE,OAAO,KAAU,cADjB,KAEA,QAAQ,KACR,eAAe,KACf,YAAY,KACZ,OAAO,EAAM,MAAO,YACpB,EAAM,GAAG,SAAS,KAClB,OAAO,EAAM,aAAc,YAC3B,EAAM,UAAU,SAAS,KACzB,OAAO,EAAM,UAAW,aACvB,EAAM,WAAW,WAChB,EAAM,WAAW,UACjB,EAAM,WAAW,iBACjB,EAAM,WAAW;;AAOvB,IAAa,KACX,MAEA,EAAM,WAAW,iBACjB,eAAe,KACf,iBAAiB,KACjB,EAAM,gBAAgB,QACtB,OAAO,EAAM,eAAgB,YAC7B,UAAU,EAAM,aAKL,KACX,MAEA,EAAM,WAAW,WACjB,eAAe,KACf,kBAAkB,KAClB,WAAW,KACX,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,YAC9B,OAAO,EAAM,SAAU,UAKZ,KAAkB,MAC7B,iBAAiB,KACjB,OAAO,EAAM,eAAgB,YAC7B,EAAM,gBAAgB,QACtB,UAAU,EAAM,eAChB,aAAa,EAAM,aAKR,KACX,MAEA,EAAe,EAAM,IAAI,EAAM,YAAY,SAAS,QAKzC,KAAiB,MAC5B,EAAM,WAAW,WACjB,YAAY,KACZ,EAAM,WAAW,QACjB,OAAO,EAAM,UAAW,YACxB,UAAU,EAAM,UAChB,eAAe,KACf,kBAAkB,KAClB,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,UAKnB,KACX,MAEA,EAAc,EAAM,KACnB,EAAM,OAAO,SAAS,uBACrB,EAAM,OAAO,SAAS,mBAKb,KACX,MAEA,EAAmB,EAAM,KACxB,EAAM,YAAY,SAAS,4BAC1B,EAAM,YAAY,SAAS,wBAKlB,KACX,MAEA,EAAmB,EAAM,IACzB,EAAM,YAAY,SAAS,iCAKhB,KACX,MAEA,EAAmB,EAAM,IAAI,EAAM,YAAY,SAAS,sBAK7C,KACX,MAEA,EAAmB,EAAM,IACzB,EAAM,YAAY,SAAS,wBAKhB,KACX,MAEA,EAAc,EAAM,IAAI,EAAM,OAAO,SAAS,yBAUnC,KACX,MAEA,EAAc,EAAM,IAAI,EAAM,cAAc,aAKjC,KACX,MAEA,EAAM,WAAW,WACjB,mBAAmB,KACnB,WAAW,KACX,OAAO,EAAM,iBAAkB,YAC/B,MAAM,QAAQ,EAAM,MAAM,EAKf,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,gCAEvB,KACX,MACmD,EAAM,QAAQ,cAEtD,KACX,MAEA,EAAM,QAAQ,oBAEH,KACX,MAC+C,EAAM,QAAQ,SAKlD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,0BAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAMvB,KAA2B,MACtC,EAAyB,EAAM,IAAI,EAAmB,EAAM,EAKjD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,sBAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS;AAUpC,SAAgB,EAAmB,GAAyC;AAC1E,QAAO,EAAY,EAAM"}
1
+ {"version":3,"file":"type-guards.js","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { StreamingDeltaEvent } from \"./core/events/streaming-delta-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for the canvas_ui custom tool's ActionEvent.\n *\n * The tool is injected via tool_module_qualnames (see canvas_ui_tool.py and\n * agent-server-adapter.ts). We discriminate on tool_name (which we control\n * via register_tool(\"canvas_ui\", ...)). The predicate narrows the event so\n * the call site can read `event.action.command` etc. without further casts.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) && event.tool_name === \"canvas_ui\";\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\nexport const isStreamingDeltaEvent = (\n event: OpenHandsEvent,\n): event is StreamingDeltaEvent =>\n \"kind\" in event && event.kind === \"StreamingDeltaEvent\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":";AAmCA,SAAgB,EAAY,GAAoC;AAC9D,QAEE,OAAO,KAAU,cADjB,KAEA,QAAQ,KACR,eAAe,KACf,YAAY,KACZ,OAAO,EAAM,MAAO,YACpB,EAAM,GAAG,SAAS,KAClB,OAAO,EAAM,aAAc,YAC3B,EAAM,UAAU,SAAS,KACzB,OAAO,EAAM,UAAW,aACvB,EAAM,WAAW,WAChB,EAAM,WAAW,UACjB,EAAM,WAAW,iBACjB,EAAM,WAAW;;AAOvB,IAAa,KACX,MAEA,EAAM,WAAW,iBACjB,eAAe,KACf,iBAAiB,KACjB,EAAM,gBAAgB,QACtB,OAAO,EAAM,eAAgB,YAC7B,UAAU,EAAM,aAKL,KACX,MAEA,EAAM,WAAW,WACjB,eAAe,KACf,kBAAkB,KAClB,WAAW,KACX,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,YAC9B,OAAO,EAAM,SAAU,UAKZ,KAAkB,MAC7B,iBAAiB,KACjB,OAAO,EAAM,eAAgB,YAC7B,EAAM,gBAAgB,QACtB,UAAU,EAAM,eAChB,aAAa,EAAM,aAKR,KACX,MAEA,EAAe,EAAM,IAAI,EAAM,YAAY,SAAS,QAKzC,KAAiB,MAC5B,EAAM,WAAW,WACjB,YAAY,KACZ,EAAM,WAAW,QACjB,OAAO,EAAM,UAAW,YACxB,UAAU,EAAM,UAChB,eAAe,KACf,kBAAkB,KAClB,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,UAKnB,KACX,MAEA,EAAc,EAAM,KACnB,EAAM,OAAO,SAAS,uBACrB,EAAM,OAAO,SAAS,mBAKb,KACX,MAEA,EAAmB,EAAM,KACxB,EAAM,YAAY,SAAS,4BAC1B,EAAM,YAAY,SAAS,wBAKlB,KACX,MAEA,EAAmB,EAAM,IACzB,EAAM,YAAY,SAAS,iCAKhB,KACX,MAEA,EAAmB,EAAM,IAAI,EAAM,YAAY,SAAS,sBAK7C,KACX,MAEA,EAAmB,EAAM,IACzB,EAAM,YAAY,SAAS,wBAKhB,KACX,MAEA,EAAc,EAAM,IAAI,EAAM,OAAO,SAAS,yBAUnC,KACX,MAEA,EAAc,EAAM,IAAI,EAAM,cAAc,aAKjC,KACX,MAEA,EAAM,WAAW,WACjB,mBAAmB,KACnB,WAAW,KACX,OAAO,EAAM,iBAAkB,YAC/B,MAAM,QAAQ,EAAM,MAAM,EAKf,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,gCAEvB,KACX,MACmD,EAAM,QAAQ,cAEtD,KACX,MAEA,EAAM,QAAQ,oBAEH,KACX,MAC+C,EAAM,QAAQ,SAKlD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,0BAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAMvB,KAA2B,MACtC,EAAyB,EAAM,IAAI,EAAmB,EAAM,EAKjD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,sBAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAEvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS;AAUpC,SAAgB,EAAmB,GAAyC;AAC1E,QAAO,EAAY,EAAM"}
@@ -1,2 +1,2 @@
1
- require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../types/agent-server/type-guards.cjs`);var t=(t,n)=>{let r=[...n];if(e.isACPToolCallEvent(t)){let n=r.findIndex(n=>e.isACPToolCallEvent(n)&&n.tool_call_id===t.tool_call_id);return n===-1?r.push(t):r[n]=t,r}if(e.isObservationEvent(t)){if(t.observation.kind===`ThinkObservation`||t.observation.kind===`FinishObservation`)return r;let e=r.findIndex(e=>e.id===t.action_id);e===-1?r.push(t):r[e]=t}else r.push(t);return r};exports.handleEventForUI=t;
1
+ require(`../_virtual/_rolldown/runtime.cjs`);const e=require(`../types/agent-server/type-guards.cjs`);var t=(e,t)=>({...t,content:`${t.content??``}${e.content??``}`||null,reasoning_content:`${t.reasoning_content??``}${e.reasoning_content??``}`||null}),n=(e,t)=>({...e,content:`${e.content??``}${t}`||null}),r=t=>{for(let n=t.length-1;n>=0;--n){let r=t[n];if(e.isMessageEvent(r)&&r.source===`user`)return n}return-1},i=e=>e.llm_message.content.filter(e=>e.type===`text`).map(e=>e.text).join(``),a=t=>e.isActionEvent(t)&&t.action.kind===`FinishAction`?t.action.message:e.isMessageEvent(t)&&t.source===`agent`?i(t):null,o=(e,t)=>{let n=0,r=0;for(let i of t){let t=e.indexOf(i,n);if(t===-1)return{matched:!1,lastMatchEnd:r};r=t+i.length,n=r}return{matched:!0,lastMatchEnd:r}},s=(t,i)=>{let s=r(i),c=i.map((e,t)=>({uiEvent:e,index:t})).filter(({uiEvent:t,index:n})=>n>s&&e.isStreamingDeltaEvent(t)).map(({index:e})=>e);if(c.length===0)return null;let l=a(t),u=c.map(e=>({event:i[e],index:e})).filter(t=>e.isStreamingDeltaEvent(t.event)&&(t.event.content?.length??0)>0),d=u.map(({event:e})=>e.content??``);if(!l||d.length===0)return null;let f=[...i],p=d.join(``),m=``;if(l.startsWith(p))m=l.slice(p.length);else{let e=o(l,d);if(!e.matched)return null;m=l.slice(e.lastMatchEnd)}let h=u.at(-1)?.index,g=h===void 0?void 0:f[h];return m&&h!==void 0&&g&&e.isStreamingDeltaEvent(g)&&(f[h]=n(g,m)),f},c=(n,r)=>{let i=[...r];if(e.isStreamingDeltaEvent(n)){if(n.content===null&&n.reasoning_content===null)return i;let r=i.length-1,a=i[r];return a&&e.isStreamingDeltaEvent(a)?(i[r]=t(n,a),i):(i.push(n),i)}if(e.isActionEvent(n)&&n.action.kind===`FinishAction`||e.isMessageEvent(n)&&n.source===`agent`){let e=s(n,i);if(e)return e}if(e.isACPToolCallEvent(n)){let t=i.findIndex(t=>e.isACPToolCallEvent(t)&&t.tool_call_id===n.tool_call_id);return t===-1?i.push(n):i[t]=n,i}if(e.isObservationEvent(n)){if(n.observation.kind===`ThinkObservation`||n.observation.kind===`FinishObservation`)return i;let e=i.findIndex(e=>e.id===n.action_id);e===-1?i.push(n):i[e]=n}else i.push(n);return i};exports.handleEventForUI=c;
2
2
  //# sourceMappingURL=handle-event-for-ui.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"handle-event-for-ui.cjs","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isObservationEvent,\n} from \"#/types/agent-server/type-guards\";\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":"sGAkBA,IAAa,GACX,EACA,IACqB,CACrB,IAAM,EAAc,CAAC,GAAG,EAAS,CAEjC,GAAI,EAAA,mBAAmB,EAAM,CAAE,CAC7B,IAAM,EAAgB,EAAY,UAC/B,GACC,EAAA,mBAAmB,EAAQ,EAC3B,EAAQ,eAAiB,EAAM,aAClC,CAMD,OALI,IAAkB,GAGpB,EAAY,KAAK,EAAM,CAFvB,EAAY,GAAiB,EAIxB,EAGT,GAAI,EAAA,mBAAmB,EAAM,CAAE,CAU7B,GAPI,EAAM,YAAY,OAAS,oBAO3B,EAAM,YAAY,OAAS,oBAC7B,OAAO,EAIT,IAAM,EAAc,EAAY,UAC7B,GAAY,EAAQ,KAAO,EAAM,UACnC,CACG,IAAgB,GAIlB,EAAY,KAAK,EAAM,CAHvB,EAAY,GAAe,OAO7B,EAAY,KAAK,EAAM,CAGzB,OAAO"}
1
+ {"version":3,"file":"handle-event-for-ui.cjs","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { MessageEvent, OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { StreamingDeltaEvent } from \"#/types/agent-server/core/events/streaming-delta-event\";\n\nconst mergeStreamingDeltaEvent = (\n incoming: StreamingDeltaEvent,\n existing: StreamingDeltaEvent,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${incoming.content ?? \"\"}` || null,\n reasoning_content:\n `${existing.reasoning_content ?? \"\"}${incoming.reasoning_content ?? \"\"}` ||\n null,\n});\n\nconst appendContentToStreamingDeltaEvent = (\n existing: StreamingDeltaEvent,\n content: string,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${content}` || null,\n});\n\nconst findLastUserMessageIndex = (events: OpenHandsEvent[]): number => {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (isMessageEvent(event) && event.source === \"user\") {\n return index;\n }\n }\n return -1;\n};\n\n// Join text blocks WITHOUT a separator: streaming deltas concatenate content\n// tokens directly with no separator between LLM content blocks, so using \"\\n\"\n// here would cause startsWith/findTextSegmentsInOrder to miss when reconciling\n// a multi-block MessageEvent against the already-rendered streaming delta.\nconst getAgentMessageText = (event: MessageEvent): string =>\n event.llm_message.content\n .filter((content) => content.type === \"text\")\n .map((content) => content.text)\n .join(\"\");\n\nconst getFinalAgentText = (event: OpenHandsEvent): string | null => {\n if (isActionEvent(event) && event.action.kind === \"FinishAction\") {\n return event.action.message;\n }\n\n if (isMessageEvent(event) && event.source === \"agent\") {\n return getAgentMessageText(event);\n }\n\n return null;\n};\n\nconst findTextSegmentsInOrder = (\n text: string,\n segments: string[],\n): { matched: boolean; lastMatchEnd: number } => {\n let searchStart = 0;\n let lastMatchEnd = 0;\n\n for (const segment of segments) {\n const index = text.indexOf(segment, searchStart);\n if (index === -1) {\n return { matched: false, lastMatchEnd };\n }\n lastMatchEnd = index + segment.length;\n searchStart = lastMatchEnd;\n }\n\n return { matched: true, lastMatchEnd };\n};\n\nconst finalizeStreamingDeltasInPlace = (\n finalEvent: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] | null => {\n const lastUserMessageIndex = findLastUserMessageIndex(uiEvents);\n const currentTurnStreamingDeltaIndexes = uiEvents\n .map((uiEvent, index) => ({ uiEvent, index }))\n .filter(\n ({ uiEvent, index }) =>\n index > lastUserMessageIndex && isStreamingDeltaEvent(uiEvent),\n )\n .map(({ index }) => index);\n\n if (currentTurnStreamingDeltaIndexes.length === 0) {\n return null;\n }\n\n const finalText = getFinalAgentText(finalEvent);\n // Only the regular `content` field participates in reconciliation.\n // Reasoning-only deltas (those that carry only `reasoning_content`) produce\n // an empty streamingSegments list, causing the function to return null so\n // the finalEvent is appended normally. This is intentional: reasoning\n // content renders in its own collapsed bubble and never overlaps with the\n // assistant's regular message text in `FinishAction.message`.\n const contentStreamingDeltas = currentTurnStreamingDeltaIndexes\n .map((index) => ({ event: uiEvents[index], index }))\n .filter(\n (item): item is { event: StreamingDeltaEvent; index: number } =>\n isStreamingDeltaEvent(item.event) &&\n (item.event.content?.length ?? 0) > 0,\n );\n const streamingSegments = contentStreamingDeltas.map(\n ({ event }) => event.content ?? \"\",\n );\n\n if (!finalText || streamingSegments.length === 0) {\n return null;\n }\n\n const nextUiEvents = [...uiEvents];\n const streamedText = streamingSegments.join(\"\");\n let unstreamedSuffix = \"\";\n\n if (finalText.startsWith(streamedText)) {\n unstreamedSuffix = finalText.slice(streamedText.length);\n } else {\n const match = findTextSegmentsInOrder(finalText, streamingSegments);\n if (!match.matched) {\n return null;\n }\n unstreamedSuffix = finalText.slice(match.lastMatchEnd);\n }\n\n const lastDeltaIndex = contentStreamingDeltas.at(-1)?.index;\n const lastDelta =\n lastDeltaIndex === undefined ? undefined : nextUiEvents[lastDeltaIndex];\n if (\n unstreamedSuffix &&\n lastDeltaIndex !== undefined &&\n lastDelta &&\n isStreamingDeltaEvent(lastDelta)\n ) {\n nextUiEvents[lastDeltaIndex] = appendContentToStreamingDeltaEvent(\n lastDelta,\n unstreamedSuffix,\n );\n }\n\n // Intentionally return nextUiEvents WITHOUT appending finalEvent.\n // The last content-bearing streaming delta (possibly extended with\n // unstreamedSuffix above) becomes the canonical final rendered bubble for\n // this turn. Appending finalEvent here would display the assistant message\n // twice.\n return nextUiEvents;\n};\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isStreamingDeltaEvent(event)) {\n if (event.content === null && event.reasoning_content === null) {\n return newUiEvents;\n }\n\n const lastIndex = newUiEvents.length - 1;\n const lastEvent = newUiEvents[lastIndex];\n if (lastEvent && isStreamingDeltaEvent(lastEvent)) {\n newUiEvents[lastIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n return newUiEvents;\n }\n\n newUiEvents.push(event);\n return newUiEvents;\n }\n\n if (\n (isActionEvent(event) && event.action.kind === \"FinishAction\") ||\n (isMessageEvent(event) && event.source === \"agent\")\n ) {\n const finalizedUiEvents = finalizeStreamingDeltasInPlace(\n event,\n newUiEvents,\n );\n if (finalizedUiEvents) {\n // The reconciled streaming delta intentionally replaces this final event\n // for rendering. Today streamed agent responses only render text and\n // reasoning content; if final-event metadata such as activated\n // microagents becomes meaningful for streamed responses, add a rendered\n // wrapper that carries both the stable delta identity and that metadata.\n return finalizedUiEvents;\n }\n }\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":"sGAUA,IAAM,GACJ,EACA,KACyB,CACzB,GAAG,EACH,QAAS,GAAG,EAAS,SAAW,KAAK,EAAS,SAAW,MAAQ,KACjE,kBACE,GAAG,EAAS,mBAAqB,KAAK,EAAS,mBAAqB,MACpE,KACH,EAEK,GACJ,EACA,KACyB,CACzB,GAAG,EACH,QAAS,GAAG,EAAS,SAAW,KAAK,KAAa,KACnD,EAEK,EAA4B,GAAqC,CACrE,IAAK,IAAI,EAAQ,EAAO,OAAS,EAAG,GAAS,EAAG,IAAY,CAC1D,IAAM,EAAQ,EAAO,GACrB,GAAI,EAAA,eAAe,EAAM,EAAI,EAAM,SAAW,OAC5C,OAAO,EAGX,MAAO,IAOH,EAAuB,GAC3B,EAAM,YAAY,QACf,OAAQ,GAAY,EAAQ,OAAS,OAAO,CAC5C,IAAK,GAAY,EAAQ,KAAK,CAC9B,KAAK,GAAG,CAEP,EAAqB,GACrB,EAAA,cAAc,EAAM,EAAI,EAAM,OAAO,OAAS,eACzC,EAAM,OAAO,QAGlB,EAAA,eAAe,EAAM,EAAI,EAAM,SAAW,QACrC,EAAoB,EAAM,CAG5B,KAGH,GACJ,EACA,IAC+C,CAC/C,IAAI,EAAc,EACd,EAAe,EAEnB,IAAK,IAAM,KAAW,EAAU,CAC9B,IAAM,EAAQ,EAAK,QAAQ,EAAS,EAAY,CAChD,GAAI,IAAU,GACZ,MAAO,CAAE,QAAS,GAAO,eAAc,CAEzC,EAAe,EAAQ,EAAQ,OAC/B,EAAc,EAGhB,MAAO,CAAE,QAAS,GAAM,eAAc,EAGlC,GACJ,EACA,IAC4B,CAC5B,IAAM,EAAuB,EAAyB,EAAS,CACzD,EAAmC,EACtC,KAAK,EAAS,KAAW,CAAE,UAAS,QAAO,EAAE,CAC7C,QACE,CAAE,UAAS,WACV,EAAQ,GAAwB,EAAA,sBAAsB,EAAQ,CACjE,CACA,KAAK,CAAE,WAAY,EAAM,CAE5B,GAAI,EAAiC,SAAW,EAC9C,OAAO,KAGT,IAAM,EAAY,EAAkB,EAAW,CAOzC,EAAyB,EAC5B,IAAK,IAAW,CAAE,MAAO,EAAS,GAAQ,QAAO,EAAE,CACnD,OACE,GACC,EAAA,sBAAsB,EAAK,MAAM,GAChC,EAAK,MAAM,SAAS,QAAU,GAAK,EACvC,CACG,EAAoB,EAAuB,KAC9C,CAAE,WAAY,EAAM,SAAW,GACjC,CAED,GAAI,CAAC,GAAa,EAAkB,SAAW,EAC7C,OAAO,KAGT,IAAM,EAAe,CAAC,GAAG,EAAS,CAC5B,EAAe,EAAkB,KAAK,GAAG,CAC3C,EAAmB,GAEvB,GAAI,EAAU,WAAW,EAAa,CACpC,EAAmB,EAAU,MAAM,EAAa,OAAO,KAClD,CACL,IAAM,EAAQ,EAAwB,EAAW,EAAkB,CACnE,GAAI,CAAC,EAAM,QACT,OAAO,KAET,EAAmB,EAAU,MAAM,EAAM,aAAa,CAGxD,IAAM,EAAiB,EAAuB,GAAG,GAAG,EAAE,MAChD,EACJ,IAAmB,IAAA,GAAY,IAAA,GAAY,EAAa,GAkB1D,OAhBE,GACA,IAAmB,IAAA,IACnB,GACA,EAAA,sBAAsB,EAAU,GAEhC,EAAa,GAAkB,EAC7B,EACA,EACD,EAQI,GAeI,GACX,EACA,IACqB,CACrB,IAAM,EAAc,CAAC,GAAG,EAAS,CAEjC,GAAI,EAAA,sBAAsB,EAAM,CAAE,CAChC,GAAI,EAAM,UAAY,MAAQ,EAAM,oBAAsB,KACxD,OAAO,EAGT,IAAM,EAAY,EAAY,OAAS,EACjC,EAAY,EAAY,GAO9B,OANI,GAAa,EAAA,sBAAsB,EAAU,EAC/C,EAAY,GAAa,EAAyB,EAAO,EAAU,CAC5D,IAGT,EAAY,KAAK,EAAM,CAChB,GAGT,GACG,EAAA,cAAc,EAAM,EAAI,EAAM,OAAO,OAAS,gBAC9C,EAAA,eAAe,EAAM,EAAI,EAAM,SAAW,QAC3C,CACA,IAAM,EAAoB,EACxB,EACA,EACD,CACD,GAAI,EAMF,OAAO,EAIX,GAAI,EAAA,mBAAmB,EAAM,CAAE,CAC7B,IAAM,EAAgB,EAAY,UAC/B,GACC,EAAA,mBAAmB,EAAQ,EAC3B,EAAQ,eAAiB,EAAM,aAClC,CAMD,OALI,IAAkB,GAGpB,EAAY,KAAK,EAAM,CAFvB,EAAY,GAAiB,EAIxB,EAGT,GAAI,EAAA,mBAAmB,EAAM,CAAE,CAU7B,GAPI,EAAM,YAAY,OAAS,oBAO3B,EAAM,YAAY,OAAS,oBAC7B,OAAO,EAIT,IAAM,EAAc,EAAY,UAC7B,GAAY,EAAQ,KAAO,EAAM,UACnC,CACG,IAAgB,GAIlB,EAAY,KAAK,EAAM,CAHvB,EAAY,GAAe,OAO7B,EAAY,KAAK,EAAM,CAGzB,OAAO"}
@@ -1,19 +1,75 @@
1
- import { isACPToolCallEvent as e, isObservationEvent as t } from "../types/agent-server/type-guards.js";
1
+ import { isACPToolCallEvent as e, isActionEvent as t, isMessageEvent as n, isObservationEvent as r, isStreamingDeltaEvent as i } from "../types/agent-server/type-guards.js";
2
2
  //#region src/utils/handle-event-for-ui.ts
3
- var n = (n, r) => {
4
- let i = [...r];
5
- if (e(n)) {
6
- let t = i.findIndex((t) => e(t) && t.tool_call_id === n.tool_call_id);
7
- return t === -1 ? i.push(n) : i[t] = n, i;
3
+ var a = (e, t) => ({
4
+ ...t,
5
+ content: `${t.content ?? ""}${e.content ?? ""}` || null,
6
+ reasoning_content: `${t.reasoning_content ?? ""}${e.reasoning_content ?? ""}` || null
7
+ }), o = (e, t) => ({
8
+ ...e,
9
+ content: `${e.content ?? ""}${t}` || null
10
+ }), s = (e) => {
11
+ for (let t = e.length - 1; t >= 0; --t) {
12
+ let r = e[t];
13
+ if (n(r) && r.source === "user") return t;
8
14
  }
9
- if (t(n)) {
10
- if (n.observation.kind === "ThinkObservation" || n.observation.kind === "FinishObservation") return i;
11
- let e = i.findIndex((e) => e.id === n.action_id);
12
- e === -1 ? i.push(n) : i[e] = n;
13
- } else i.push(n);
14
- return i;
15
+ return -1;
16
+ }, c = (e) => e.llm_message.content.filter((e) => e.type === "text").map((e) => e.text).join(""), l = (e) => t(e) && e.action.kind === "FinishAction" ? e.action.message : n(e) && e.source === "agent" ? c(e) : null, u = (e, t) => {
17
+ let n = 0, r = 0;
18
+ for (let i of t) {
19
+ let t = e.indexOf(i, n);
20
+ if (t === -1) return {
21
+ matched: !1,
22
+ lastMatchEnd: r
23
+ };
24
+ r = t + i.length, n = r;
25
+ }
26
+ return {
27
+ matched: !0,
28
+ lastMatchEnd: r
29
+ };
30
+ }, d = (e, t) => {
31
+ let n = s(t), r = t.map((e, t) => ({
32
+ uiEvent: e,
33
+ index: t
34
+ })).filter(({ uiEvent: e, index: t }) => t > n && i(e)).map(({ index: e }) => e);
35
+ if (r.length === 0) return null;
36
+ let a = l(e), c = r.map((e) => ({
37
+ event: t[e],
38
+ index: e
39
+ })).filter((e) => i(e.event) && (e.event.content?.length ?? 0) > 0), d = c.map(({ event: e }) => e.content ?? "");
40
+ if (!a || d.length === 0) return null;
41
+ let f = [...t], p = d.join(""), m = "";
42
+ if (a.startsWith(p)) m = a.slice(p.length);
43
+ else {
44
+ let e = u(a, d);
45
+ if (!e.matched) return null;
46
+ m = a.slice(e.lastMatchEnd);
47
+ }
48
+ let h = c.at(-1)?.index, g = h === void 0 ? void 0 : f[h];
49
+ return m && h !== void 0 && g && i(g) && (f[h] = o(g, m)), f;
50
+ }, f = (o, s) => {
51
+ let c = [...s];
52
+ if (i(o)) {
53
+ if (o.content === null && o.reasoning_content === null) return c;
54
+ let e = c.length - 1, t = c[e];
55
+ return t && i(t) ? (c[e] = a(o, t), c) : (c.push(o), c);
56
+ }
57
+ if (t(o) && o.action.kind === "FinishAction" || n(o) && o.source === "agent") {
58
+ let e = d(o, c);
59
+ if (e) return e;
60
+ }
61
+ if (e(o)) {
62
+ let t = c.findIndex((t) => e(t) && t.tool_call_id === o.tool_call_id);
63
+ return t === -1 ? c.push(o) : c[t] = o, c;
64
+ }
65
+ if (r(o)) {
66
+ if (o.observation.kind === "ThinkObservation" || o.observation.kind === "FinishObservation") return c;
67
+ let e = c.findIndex((e) => e.id === o.action_id);
68
+ e === -1 ? c.push(o) : c[e] = o;
69
+ } else c.push(o);
70
+ return c;
15
71
  };
16
72
  //#endregion
17
- export { n as handleEventForUI };
73
+ export { f as handleEventForUI };
18
74
 
19
75
  //# sourceMappingURL=handle-event-for-ui.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handle-event-for-ui.js","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isObservationEvent,\n} from \"#/types/agent-server/type-guards\";\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":";;AAkBA,IAAa,KACX,GACA,MACqB;CACrB,IAAM,IAAc,CAAC,GAAG,EAAS;AAEjC,KAAI,EAAmB,EAAM,EAAE;EAC7B,IAAM,IAAgB,EAAY,WAC/B,MACC,EAAmB,EAAQ,IAC3B,EAAQ,iBAAiB,EAAM,aAClC;AAMD,SALI,MAAkB,KAGpB,EAAY,KAAK,EAAM,GAFvB,EAAY,KAAiB,GAIxB;;AAGT,KAAI,EAAmB,EAAM,EAAE;AAU7B,MAPI,EAAM,YAAY,SAAS,sBAO3B,EAAM,YAAY,SAAS,oBAC7B,QAAO;EAIT,IAAM,IAAc,EAAY,WAC7B,MAAY,EAAQ,OAAO,EAAM,UACnC;AACD,EAAI,MAAgB,KAIlB,EAAY,KAAK,EAAM,GAHvB,EAAY,KAAe;OAO7B,GAAY,KAAK,EAAM;AAGzB,QAAO"}
1
+ {"version":3,"file":"handle-event-for-ui.js","names":[],"sources":["../../src/utils/handle-event-for-ui.ts"],"sourcesContent":["import { MessageEvent, OpenHandsEvent } from \"#/types/agent-server/core\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { StreamingDeltaEvent } from \"#/types/agent-server/core/events/streaming-delta-event\";\n\nconst mergeStreamingDeltaEvent = (\n incoming: StreamingDeltaEvent,\n existing: StreamingDeltaEvent,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${incoming.content ?? \"\"}` || null,\n reasoning_content:\n `${existing.reasoning_content ?? \"\"}${incoming.reasoning_content ?? \"\"}` ||\n null,\n});\n\nconst appendContentToStreamingDeltaEvent = (\n existing: StreamingDeltaEvent,\n content: string,\n): StreamingDeltaEvent => ({\n ...existing,\n content: `${existing.content ?? \"\"}${content}` || null,\n});\n\nconst findLastUserMessageIndex = (events: OpenHandsEvent[]): number => {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (isMessageEvent(event) && event.source === \"user\") {\n return index;\n }\n }\n return -1;\n};\n\n// Join text blocks WITHOUT a separator: streaming deltas concatenate content\n// tokens directly with no separator between LLM content blocks, so using \"\\n\"\n// here would cause startsWith/findTextSegmentsInOrder to miss when reconciling\n// a multi-block MessageEvent against the already-rendered streaming delta.\nconst getAgentMessageText = (event: MessageEvent): string =>\n event.llm_message.content\n .filter((content) => content.type === \"text\")\n .map((content) => content.text)\n .join(\"\");\n\nconst getFinalAgentText = (event: OpenHandsEvent): string | null => {\n if (isActionEvent(event) && event.action.kind === \"FinishAction\") {\n return event.action.message;\n }\n\n if (isMessageEvent(event) && event.source === \"agent\") {\n return getAgentMessageText(event);\n }\n\n return null;\n};\n\nconst findTextSegmentsInOrder = (\n text: string,\n segments: string[],\n): { matched: boolean; lastMatchEnd: number } => {\n let searchStart = 0;\n let lastMatchEnd = 0;\n\n for (const segment of segments) {\n const index = text.indexOf(segment, searchStart);\n if (index === -1) {\n return { matched: false, lastMatchEnd };\n }\n lastMatchEnd = index + segment.length;\n searchStart = lastMatchEnd;\n }\n\n return { matched: true, lastMatchEnd };\n};\n\nconst finalizeStreamingDeltasInPlace = (\n finalEvent: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] | null => {\n const lastUserMessageIndex = findLastUserMessageIndex(uiEvents);\n const currentTurnStreamingDeltaIndexes = uiEvents\n .map((uiEvent, index) => ({ uiEvent, index }))\n .filter(\n ({ uiEvent, index }) =>\n index > lastUserMessageIndex && isStreamingDeltaEvent(uiEvent),\n )\n .map(({ index }) => index);\n\n if (currentTurnStreamingDeltaIndexes.length === 0) {\n return null;\n }\n\n const finalText = getFinalAgentText(finalEvent);\n // Only the regular `content` field participates in reconciliation.\n // Reasoning-only deltas (those that carry only `reasoning_content`) produce\n // an empty streamingSegments list, causing the function to return null so\n // the finalEvent is appended normally. This is intentional: reasoning\n // content renders in its own collapsed bubble and never overlaps with the\n // assistant's regular message text in `FinishAction.message`.\n const contentStreamingDeltas = currentTurnStreamingDeltaIndexes\n .map((index) => ({ event: uiEvents[index], index }))\n .filter(\n (item): item is { event: StreamingDeltaEvent; index: number } =>\n isStreamingDeltaEvent(item.event) &&\n (item.event.content?.length ?? 0) > 0,\n );\n const streamingSegments = contentStreamingDeltas.map(\n ({ event }) => event.content ?? \"\",\n );\n\n if (!finalText || streamingSegments.length === 0) {\n return null;\n }\n\n const nextUiEvents = [...uiEvents];\n const streamedText = streamingSegments.join(\"\");\n let unstreamedSuffix = \"\";\n\n if (finalText.startsWith(streamedText)) {\n unstreamedSuffix = finalText.slice(streamedText.length);\n } else {\n const match = findTextSegmentsInOrder(finalText, streamingSegments);\n if (!match.matched) {\n return null;\n }\n unstreamedSuffix = finalText.slice(match.lastMatchEnd);\n }\n\n const lastDeltaIndex = contentStreamingDeltas.at(-1)?.index;\n const lastDelta =\n lastDeltaIndex === undefined ? undefined : nextUiEvents[lastDeltaIndex];\n if (\n unstreamedSuffix &&\n lastDeltaIndex !== undefined &&\n lastDelta &&\n isStreamingDeltaEvent(lastDelta)\n ) {\n nextUiEvents[lastDeltaIndex] = appendContentToStreamingDeltaEvent(\n lastDelta,\n unstreamedSuffix,\n );\n }\n\n // Intentionally return nextUiEvents WITHOUT appending finalEvent.\n // The last content-bearing streaming delta (possibly extended with\n // unstreamedSuffix above) becomes the canonical final rendered bubble for\n // this turn. Appending finalEvent here would display the assistant message\n // twice.\n return nextUiEvents;\n};\n\n/**\n * Handles adding an event to the UI events array\n * Replaces actions with observations when they arrive (so UI shows observation instead of action)\n * Exception: ThinkAction is NOT replaced because the thought content is in the action, not in the observation\n *\n * ACPToolCallEvent merge: the SDK emits two events per ``tool_call_id`` — an\n * early ``started`` event (``pending`` / ``in_progress``) and one terminal\n * (completed / failed) event, the action->observation pair for a tool call.\n * Replace the started entry in place with the terminal one so a single card\n * updates from running to its result, exactly like an observation superseding\n * its action below.\n */\nexport const handleEventForUI = (\n event: OpenHandsEvent,\n uiEvents: OpenHandsEvent[],\n): OpenHandsEvent[] => {\n const newUiEvents = [...uiEvents];\n\n if (isStreamingDeltaEvent(event)) {\n if (event.content === null && event.reasoning_content === null) {\n return newUiEvents;\n }\n\n const lastIndex = newUiEvents.length - 1;\n const lastEvent = newUiEvents[lastIndex];\n if (lastEvent && isStreamingDeltaEvent(lastEvent)) {\n newUiEvents[lastIndex] = mergeStreamingDeltaEvent(event, lastEvent);\n return newUiEvents;\n }\n\n newUiEvents.push(event);\n return newUiEvents;\n }\n\n if (\n (isActionEvent(event) && event.action.kind === \"FinishAction\") ||\n (isMessageEvent(event) && event.source === \"agent\")\n ) {\n const finalizedUiEvents = finalizeStreamingDeltasInPlace(\n event,\n newUiEvents,\n );\n if (finalizedUiEvents) {\n // The reconciled streaming delta intentionally replaces this final event\n // for rendering. Today streamed agent responses only render text and\n // reasoning content; if final-event metadata such as activated\n // microagents becomes meaningful for streamed responses, add a rendered\n // wrapper that carries both the stable delta identity and that metadata.\n return finalizedUiEvents;\n }\n }\n\n if (isACPToolCallEvent(event)) {\n const existingIndex = newUiEvents.findIndex(\n (uiEvent) =>\n isACPToolCallEvent(uiEvent) &&\n uiEvent.tool_call_id === event.tool_call_id,\n );\n if (existingIndex !== -1) {\n newUiEvents[existingIndex] = event;\n } else {\n newUiEvents.push(event);\n }\n return newUiEvents;\n }\n\n if (isObservationEvent(event)) {\n // Don't add ThinkObservation at all - we keep the ThinkAction instead\n // The thought content is in the action, not the observation\n if (event.observation.kind === \"ThinkObservation\") {\n return newUiEvents;\n }\n\n // Don't add FinishObservation at all - we keep the FinishAction instead\n // Both contain the same message content, so we only need to display one\n // This also prevents duplicate messages when events arrive out of order due to React batching\n if (event.observation.kind === \"FinishObservation\") {\n return newUiEvents;\n }\n\n // Find and replace the corresponding action from uiEvents\n const actionIndex = newUiEvents.findIndex(\n (uiEvent) => uiEvent.id === event.action_id,\n );\n if (actionIndex !== -1) {\n newUiEvents[actionIndex] = event;\n } else {\n // Action not found in uiEvents, just add the observation\n newUiEvents.push(event);\n }\n } else {\n // For non-observation events, just add them to uiEvents\n newUiEvents.push(event);\n }\n\n return newUiEvents;\n};\n"],"mappings":"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"}