@openhands/agent-canvas 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/README.md +1 -1
  2. package/README.windows.md +2 -2
  3. package/build/assets/{Trans-De9RwQhA.js → Trans-DY6toRDu.js} +1 -1
  4. package/build/assets/{acp-providers-D_D8VUpP.js → acp-providers-Djl6vNn-.js} +1 -1
  5. package/build/assets/active-backend-context-B3umL5R-.js +1 -0
  6. package/build/assets/{add-backend-modal-DIEyAkA4.js → add-backend-modal-DljoP9lc.js} +1 -1
  7. package/build/assets/{agent-profiles-settings-BovdV4N8.js → agent-profiles-settings-BJMmTZgv.js} +1 -1
  8. package/build/assets/{agent-server-conversation-service.api-BP73yONA.js → agent-server-conversation-service.api-D_ZvtJjG.js} +3 -3
  9. package/build/assets/agent-settings-BVVFzBWS.js +1 -0
  10. package/build/assets/{agent-settings-Ofbh6UTD.js → agent-settings-lUknCeaF.js} +1 -1
  11. package/build/assets/{alert-banner-BW0wRYw6.js → alert-banner-Bpf2NQJq.js} +1 -1
  12. package/build/assets/{api-key-entry-screen-CZIdRmUJ.js → api-key-entry-screen-CWEHcPJA.js} +1 -1
  13. package/build/assets/{app-settings-BHJ9nKti.js → app-settings-Dj90qosy.js} +1 -1
  14. package/build/assets/automation-detail-CXJU0_gF.js +2 -0
  15. package/build/assets/automation-export-FWY9LPsG.js +2 -0
  16. package/build/assets/automations-list-DDGBkWLC.js +1 -0
  17. package/build/assets/{back-nav-button-BYmxFxGt.js → back-nav-button-CUS2mi-U.js} +1 -1
  18. package/build/assets/{backend-form-modal-BiaOB2C4.js → backend-form-modal-DSbrafX2.js} +1 -1
  19. package/build/assets/{backend-synced-settings-badge-Bs3FSXsS.js → backend-synced-settings-badge-CanzmG12.js} +1 -1
  20. package/build/assets/{base-modal-CC5Pp8CF.js → base-modal-BuF2f0YL.js} +1 -1
  21. package/build/assets/{brand-button-DKPMEKcW.js → brand-button-vMVuyDXu.js} +1 -1
  22. package/build/assets/{browser-B39N74jU.js → browser-BifzWIBd.js} +1 -1
  23. package/build/assets/{browser-tab-aiDg7aEn.js → browser-tab-CkkqJnqw.js} +1 -1
  24. package/build/assets/{chat-send-button-DxuZIoW8.js → chat-send-button-B_jc5z5C.js} +1 -1
  25. package/build/assets/{circle-plus-check-toggle-T3eAIuPQ.js → circle-plus-check-toggle-C5YxjxvI.js} +1 -1
  26. package/build/assets/{combobox-caret-CLGvOs32.js → combobox-caret-DoObzqf4.js} +1 -1
  27. package/build/assets/{command-menu-DKrLCRla.js → command-menu-D-JV3Wqm.js} +1 -1
  28. package/build/assets/{condenser-settings-D_5vY4m3.js → condenser-settings-30cX9SK6.js} +1 -1
  29. package/build/assets/{confirmation-modal-BK1F0A68.js → confirmation-modal-BGLu6XJN.js} +1 -1
  30. package/build/assets/{context-menu-list-item-DBFzplWW.js → context-menu-list-item-BD5_EaKN.js} +1 -1
  31. package/build/assets/conversation-BltULtFA.js +89 -0
  32. package/build/assets/conversation-e0a0_X4S.js +1 -0
  33. package/build/assets/conversation-panel-Cr9_ZGI-.js +1 -0
  34. package/build/assets/{conversation-service.api-CqZcHr1c.js → conversation-service.api-DQaKzIRj.js} +1 -1
  35. package/build/assets/{conversation-tab-empty-state-m8IUkfMj.js → conversation-tab-empty-state-B2dDYEwf.js} +1 -1
  36. package/build/assets/{copy-to-clipboard-button-Aj9wFmt2.js → copy-to-clipboard-button-CaR52OnA.js} +1 -1
  37. package/build/assets/declaration-gq8V5eTU.js +1 -0
  38. package/build/assets/{device-verify-B5YCrvSu.js → device-verify-BsznkV-a.js} +1 -1
  39. package/build/assets/{dropdown-classes-CgQ45JmQ.js → dropdown-classes-DJSXeLqc.js} +1 -1
  40. package/build/assets/{ellipsis-button-1BV9Sga8.js → ellipsis-button-C5Z-tPFp.js} +1 -1
  41. package/build/assets/{entry.client-Dy--3GeA.js → entry.client-JixNvFrr.js} +2 -2
  42. package/build/assets/{enum-filter-dropdown-DCITiYVi.js → enum-filter-dropdown-DXbVwiNZ.js} +1 -1
  43. package/build/assets/{environment-switch-overlay-DUnKILNH.js → environment-switch-overlay-DZQfRGTx.js} +1 -1
  44. package/build/assets/{extensions-hub-CksKNpP9.js → extensions-hub-DfvgqzTc.js} +1 -1
  45. package/build/assets/{extensions-navigation-Di9rJ-b5.js → extensions-navigation-D9i0DL62.js} +1 -1
  46. package/build/assets/files-tab-DDtEJcGE.js +1 -0
  47. package/build/assets/{form-control-classes-9rkU4usZ.js → form-control-classes-ChpNBe9n.js} +1 -1
  48. package/build/assets/{git-provider-icon-aQRcUVI-.js → git-provider-icon-BjkecAuV.js} +1 -1
  49. package/build/assets/home-BCKWpKpf.js +1 -0
  50. package/build/assets/{install-server-modal-BRab9inF.js → install-server-modal-BIugLhVB.js} +1 -1
  51. package/build/assets/{launch-1TJRKkkX.js → launch-BgIlZLSX.js} +1 -1
  52. package/build/assets/lesson-plan-DgpP80mJ.js +4 -0
  53. package/build/assets/{llm-not-configured-banner-BrU5uHto.js → llm-not-configured-banner-BlX8NifC.js} +4 -4
  54. package/build/assets/llm-settings-DJmbryaE.js +1 -0
  55. package/build/assets/{llm-settings-BpdU51Jo.js → llm-settings-kU5v0H1Z.js} +1 -1
  56. package/build/assets/{loading-spinner-DHAIPZkP.js → loading-spinner-BLdswi6q.js} +1 -1
  57. package/build/assets/{manage-backends-modal-BREySP-J.js → manage-backends-modal-C8FJQIZR.js} +1 -1
  58. package/build/assets/manifest-56d40d7c.js +1 -0
  59. package/build/assets/{markdown-renderer-D8mayGjI.js → markdown-renderer-DMT7Zkpd.js} +1 -1
  60. package/build/assets/{mcp-XXf8k6mb.js → mcp-CHkklDMv.js} +1 -1
  61. package/build/assets/{messages-D2oZb47Z.js → messages-B3RugH7P.js} +11 -11
  62. package/build/assets/{modal-body-Dcu5McCa.js → modal-body-DouOE5KH.js} +1 -1
  63. package/build/assets/{modal-classes-DPqxSyuP.js → modal-classes-Cf-4tbHz.js} +1 -1
  64. package/build/assets/{modal-close-button-CTCX4nCH.js → modal-close-button-B6CfxxJj.js} +1 -1
  65. package/build/assets/{model-selector-VDHBytb6.js → model-selector-BOj1wBlq.js} +1 -1
  66. package/build/assets/onboarding-DYhDxmI9.js +1 -0
  67. package/build/assets/{onboarding-modal-C084vkv7.js → onboarding-modal-CP_WxDC9.js} +1 -1
  68. package/build/assets/{option-service.api-Cl5VLGyw.js → option-service.api-C0tYT4-r.js} +1 -1
  69. package/build/assets/{path-utils-BeOmjIcE.js → path-utils-DWcgCGen.js} +1 -1
  70. package/build/assets/{plan-components-j9X4AxYM.js → plan-components-CcCBmCzW.js} +1 -1
  71. package/build/assets/{planner-tab-AZMjJx31.js → planner-tab-CCqdXxkL.js} +1 -1
  72. package/build/assets/providers-BxCuC9bZ.js +1 -0
  73. package/build/assets/{recommended-automations-launcher-Bk8tQ-Cn.js → recommended-automations-launcher-CVEF_1pc.js} +1 -1
  74. package/build/assets/root-V8fkplMy.css +1 -0
  75. package/build/assets/root-layout-CttG_lQi.js +2 -0
  76. package/build/assets/{root-tuEPDx-i.js → root-uJ2t9rCQ.js} +2 -2
  77. package/build/assets/{runtime-waiting-state-DkzLgvMn.js → runtime-waiting-state-BsXLElvN.js} +1 -1
  78. package/build/assets/{schema-field-nvq_Juo2.js → schema-field-xUr6rDd6.js} +1 -1
  79. package/build/assets/{sdk-section-page-CgT70FaZ.js → sdk-section-page-CbLrVUa3.js} +1 -1
  80. package/build/assets/{sdk-settings-schema-BjBkMHzZ.js → sdk-settings-schema-Cv7M9eSe.js} +1 -1
  81. package/build/assets/{secrets-settings-BCxk9p9s.js → secrets-settings-DxTx9HgU.js} +1 -1
  82. package/build/assets/{segmented-toggle-Cen5AMUc.js → segmented-toggle-DyQqPhoD.js} +1 -1
  83. package/build/assets/{settings-CedTdtb5.js → settings-DnlfS09K.js} +1 -1
  84. package/build/assets/{settings-dropdown-input-xzoZwgUe.js → settings-dropdown-input-BjunGXJb.js} +1 -1
  85. package/build/assets/{settings-index-Cct3PJSP.js → settings-index-BjeuYFFa.js} +1 -1
  86. package/build/assets/{settings-input-DYs7t3oK.js → settings-input-bD6npsDm.js} +1 -1
  87. package/build/assets/{settings-list-classes-DvQr5jVS.js → settings-list-classes-Dp_OgzN0.js} +1 -1
  88. package/build/assets/{settings-modal-DwLybV_O.js → settings-modal-DfTcL-mV.js} +1 -1
  89. package/build/assets/settings-service.api-K4ncGlBv.js +1 -0
  90. package/build/assets/{settings-switch-C2N2xqEb.js → settings-switch-5cuxl8Dc.js} +1 -1
  91. package/build/assets/{shared-conversation-DnDwfLgg.js → shared-conversation-DWtBkJv7.js} +1 -1
  92. package/build/assets/{sidebar-layout-BtpUSN3j.js → sidebar-layout-DuzJMMw-.js} +1 -1
  93. package/build/assets/{sidebar-mobile-menu-toggle-B8k3qu84.js → sidebar-mobile-menu-toggle-CMmAYkh8.js} +1 -1
  94. package/build/assets/{sidebar-nav-link-CIB3NBRW.js → sidebar-nav-link-5AlTT5-j.js} +1 -1
  95. package/build/assets/{skill-card-pill-row-D2bUe2kB.js → skill-card-pill-row-eTIkE4nz.js} +1 -1
  96. package/build/assets/{skills-plugins-B68ay6Pu.js → skills-plugins-BJ040luO.js} +1 -1
  97. package/build/assets/{skills-settings-A6sUy0T7.js → skills-settings-BYn4-AQQ.js} +1 -1
  98. package/build/assets/{styled-tooltip-DsKsFjuq.js → styled-tooltip-CgX2oRaK.js} +1 -1
  99. package/build/assets/{task-list-tab-BAThr9Ex.js → task-list-tab-0k9PhuqO.js} +1 -1
  100. package/build/assets/{terminal-BmT0_gIH.js → terminal-BsGcSpRS.js} +1 -1
  101. package/build/assets/{toggle-switch-DBlOOzBr.js → toggle-switch-2j5wwR85.js} +1 -1
  102. package/build/assets/{typography-YGPBGzOG.js → typography-D8mHDeNG.js} +1 -1
  103. package/build/assets/{use-acp-credential-form-Bs6s0DTU.js → use-acp-credential-form-EtnbtYt0.js} +1 -1
  104. package/build/assets/{use-activate-agent-profile-CKtTToSx.js → use-activate-agent-profile-WaAZYz4E.js} +1 -1
  105. package/build/assets/{use-active-agent-profile-CWLPpOtK.js → use-active-agent-profile-CYY3vGar.js} +1 -1
  106. package/build/assets/{use-active-conversation-DI5S5M1w.js → use-active-conversation-D-r929nx.js} +1 -1
  107. package/build/assets/{use-agent-profiles-DPcaYLpm.js → use-agent-profiles-DEAMFp-W.js} +1 -1
  108. package/build/assets/{use-agent-state-Buh3bQDh.js → use-agent-state-DijdVAQ0.js} +1 -1
  109. package/build/assets/{use-backends-health-CxkvJy2N.js → use-backends-health-DkC7tKkC.js} +1 -1
  110. package/build/assets/{use-can-manage-org-profiles-DeX2Mfje.js → use-can-manage-org-profiles-BEo0peGn.js} +1 -1
  111. package/build/assets/{use-cloud-current-user-id-D_PQGfmT.js → use-cloud-current-user-id-Dm99wXp2.js} +1 -1
  112. package/build/assets/{use-config-ur0RbjCP.js → use-config-CHzNIHpv.js} +1 -1
  113. package/build/assets/{use-create-conversation-D9OWYcte.js → use-create-conversation-CTsvZ96U.js} +1 -1
  114. package/build/assets/{use-create-secret-CVFSlhlR.js → use-create-secret-D5O5qdWC.js} +1 -1
  115. package/build/assets/{use-event-store-YSOxy9FC.js → use-event-store-DjgU4wfO.js} +1 -1
  116. package/build/assets/{use-handle-plan-click-Dug8egQl.js → use-handle-plan-click-Mn_SNTCh.js} +1 -1
  117. package/build/assets/{use-llm-profiles-DjackuP1.js → use-llm-profiles-BMhPDlwQ.js} +1 -1
  118. package/build/assets/use-runtime-is-ready-CC-KrLKe.js +1 -0
  119. package/build/assets/{use-save-agent-profile-aKKLqDJM.js → use-save-agent-profile-CLMmbx_X.js} +1 -1
  120. package/build/assets/{use-save-settings-CChDyjOB.js → use-save-settings-D1HoCDbn.js} +1 -1
  121. package/build/assets/{use-settings-dX4fKUPF.js → use-settings-BReAMxCG.js} +1 -1
  122. package/build/assets/{use-settings-nav-items-D6pHnvxg.js → use-settings-nav-items-xe1YgLnE.js} +1 -1
  123. package/build/assets/{use-task-list-CmWGElgb.js → use-task-list-AVBLbbcR.js} +1 -1
  124. package/build/assets/{use-tracking-GtXCHmTv.js → use-tracking-2ZwQwpg_.js} +1 -1
  125. package/build/assets/{use-user-conversation-6uOXFP95.js → use-user-conversation-OAfenBRG.js} +1 -1
  126. package/build/assets/{useTranslation-Cgy4JA_g.js → useTranslation-CDRCKC9-.js} +1 -1
  127. package/build/assets/{utils-CE0lDWtb.js → utils-D3U3rlqr.js} +1 -1
  128. package/build/assets/{verification-settings-D_zsNB_c.js → verification-settings-DnXS6VWv.js} +1 -1
  129. package/build/index.html +4 -4
  130. package/build/locales/ar/openhands.json +24 -0
  131. package/build/locales/ca/openhands.json +24 -0
  132. package/build/locales/de/openhands.json +24 -0
  133. package/build/locales/en/openhands.json +24 -0
  134. package/build/locales/es/openhands.json +24 -0
  135. package/build/locales/fr/openhands.json +24 -0
  136. package/build/locales/it/openhands.json +24 -0
  137. package/build/locales/ja/openhands.json +24 -0
  138. package/build/locales/ko-KR/openhands.json +24 -0
  139. package/build/locales/no/openhands.json +24 -0
  140. package/build/locales/pt/openhands.json +24 -0
  141. package/build/locales/tr/openhands.json +24 -0
  142. package/build/locales/uk/openhands.json +24 -0
  143. package/build/locales/zh-CN/openhands.json +24 -0
  144. package/build/locales/zh-TW/openhands.json +24 -0
  145. package/config/defaults.json +4 -4
  146. package/dist/api/automation-service/automation-service.api.d.ts +2 -1
  147. package/dist/api/event-service/event-service.api.cjs +1 -1
  148. package/dist/api/event-service/event-service.api.cjs.map +1 -1
  149. package/dist/api/event-service/event-service.api.js +1 -1
  150. package/dist/api/event-service/event-service.api.js.map +1 -1
  151. package/dist/api/event-service/event-service.types.d.ts +6 -0
  152. package/dist/api/git-service/agent-server-git-service.api.cjs +1 -1
  153. package/dist/api/git-service/agent-server-git-service.api.cjs.map +1 -1
  154. package/dist/api/git-service/agent-server-git-service.api.js +2 -2
  155. package/dist/api/git-service/agent-server-git-service.api.js.map +1 -1
  156. package/dist/api/git-service/git-service.api.cjs +1 -1
  157. package/dist/api/git-service/git-service.api.cjs.map +1 -1
  158. package/dist/api/git-service/git-service.api.js +2 -2
  159. package/dist/api/git-service/git-service.api.js.map +1 -1
  160. package/dist/components/conversation-events/chat/event-thought-helpers.cjs +1 -1
  161. package/dist/components/conversation-events/chat/event-thought-helpers.js +1 -1
  162. package/dist/components/features/automations/automation-card.d.ts +2 -1
  163. package/dist/components/features/automations/automation-group.d.ts +2 -1
  164. package/dist/components/features/automations/automation-list-row.d.ts +2 -1
  165. package/dist/components/features/automations/build-automation-menu-items.d.ts +2 -1
  166. package/dist/components/features/automations/detail/detail-header.d.ts +3 -1
  167. package/dist/components/features/automations/import-automation-modal.d.ts +10 -0
  168. package/dist/components/features/conversation/conversation-name-context-menu.cjs +1 -1
  169. package/dist/components/features/conversation/conversation-name-context-menu.cjs.map +1 -1
  170. package/dist/components/features/conversation/conversation-name-context-menu.d.ts +2 -1
  171. package/dist/components/features/conversation/conversation-name-context-menu.js +74 -63
  172. package/dist/components/features/conversation/conversation-name-context-menu.js.map +1 -1
  173. package/dist/components/features/conversation/conversation-name.cjs +1 -1
  174. package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
  175. package/dist/components/features/conversation/conversation-name.js +73 -61
  176. package/dist/components/features/conversation/conversation-name.js.map +1 -1
  177. package/dist/components/features/conversation/transcript-export-modal.cjs +2 -0
  178. package/dist/components/features/conversation/transcript-export-modal.cjs.map +1 -0
  179. package/dist/components/features/conversation/transcript-export-modal.d.ts +10 -0
  180. package/dist/components/features/conversation/transcript-export-modal.js +140 -0
  181. package/dist/components/features/conversation/transcript-export-modal.js.map +1 -0
  182. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs +1 -1
  183. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs.map +1 -1
  184. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js +1 -1
  185. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js.map +1 -1
  186. package/dist/components/features/home/shared/dropdown-item.cjs +1 -1
  187. package/dist/components/features/home/shared/dropdown-item.cjs.map +1 -1
  188. package/dist/components/features/home/shared/dropdown-item.d.ts +7 -1
  189. package/dist/components/features/home/shared/dropdown-item.js +2 -1
  190. package/dist/components/features/home/shared/dropdown-item.js.map +1 -1
  191. package/dist/components/features/home/shared/generic-dropdown-menu.cjs +1 -1
  192. package/dist/components/features/home/shared/generic-dropdown-menu.cjs.map +1 -1
  193. package/dist/components/features/home/shared/generic-dropdown-menu.d.ts +8 -1
  194. package/dist/components/features/home/shared/generic-dropdown-menu.js +18 -10
  195. package/dist/components/features/home/shared/generic-dropdown-menu.js.map +1 -1
  196. package/dist/components/features/home/workspace-dropdown/workspace-dropdown.d.ts +11 -2
  197. package/dist/config/defaults.cjs +1 -1
  198. package/dist/config/defaults.cjs.map +1 -1
  199. package/dist/config/defaults.js +4 -4
  200. package/dist/config/defaults.js.map +1 -1
  201. package/dist/hooks/query/use-automations.d.ts +2 -1
  202. package/dist/hooks/query/use-resolved-workspaces.cjs +1 -1
  203. package/dist/hooks/query/use-resolved-workspaces.cjs.map +1 -1
  204. package/dist/hooks/query/use-resolved-workspaces.d.ts +9 -1
  205. package/dist/hooks/query/use-resolved-workspaces.js +1 -0
  206. package/dist/hooks/query/use-resolved-workspaces.js.map +1 -1
  207. package/dist/hooks/query/use-workspace-file-content.cjs +1 -1
  208. package/dist/hooks/query/use-workspace-file-content.cjs.map +1 -1
  209. package/dist/hooks/query/use-workspace-file-content.js +61 -55
  210. package/dist/hooks/query/use-workspace-file-content.js.map +1 -1
  211. package/dist/hooks/query/use-workspace-files.cjs +1 -1
  212. package/dist/hooks/query/use-workspace-files.cjs.map +1 -1
  213. package/dist/hooks/query/use-workspace-files.d.ts +11 -4
  214. package/dist/hooks/query/use-workspace-files.js +39 -18
  215. package/dist/hooks/query/use-workspace-files.js.map +1 -1
  216. package/dist/hooks/use-auto-refresh-files-on-edit.cjs +1 -1
  217. package/dist/hooks/use-auto-refresh-files-on-edit.cjs.map +1 -1
  218. package/dist/hooks/use-auto-refresh-files-on-edit.d.ts +9 -0
  219. package/dist/hooks/use-auto-refresh-files-on-edit.js +15 -11
  220. package/dist/hooks/use-auto-refresh-files-on-edit.js.map +1 -1
  221. package/dist/hooks/use-tracking.cjs +1 -1
  222. package/dist/hooks/use-tracking.cjs.map +1 -1
  223. package/dist/hooks/use-tracking.d.ts +7 -0
  224. package/dist/hooks/use-tracking.js +9 -0
  225. package/dist/hooks/use-tracking.js.map +1 -1
  226. package/dist/i18n/declaration.cjs +1 -1
  227. package/dist/i18n/declaration.cjs.map +1 -1
  228. package/dist/i18n/declaration.d.ts +24 -0
  229. package/dist/i18n/declaration.js +1 -1
  230. package/dist/i18n/declaration.js.map +1 -1
  231. package/dist/i18n/translation.cjs +1 -1
  232. package/dist/i18n/translation.cjs.map +1 -1
  233. package/dist/i18n/translation.js +408 -0
  234. package/dist/i18n/translation.js.map +1 -1
  235. package/dist/locales/ar/openhands.json +24 -0
  236. package/dist/locales/ca/openhands.json +24 -0
  237. package/dist/locales/de/openhands.json +24 -0
  238. package/dist/locales/en/openhands.json +24 -0
  239. package/dist/locales/es/openhands.json +24 -0
  240. package/dist/locales/fr/openhands.json +24 -0
  241. package/dist/locales/it/openhands.json +24 -0
  242. package/dist/locales/ja/openhands.json +24 -0
  243. package/dist/locales/ko-KR/openhands.json +24 -0
  244. package/dist/locales/no/openhands.json +24 -0
  245. package/dist/locales/pt/openhands.json +24 -0
  246. package/dist/locales/tr/openhands.json +24 -0
  247. package/dist/locales/uk/openhands.json +24 -0
  248. package/dist/locales/zh-CN/openhands.json +24 -0
  249. package/dist/locales/zh-TW/openhands.json +24 -0
  250. package/dist/package.cjs +1 -1
  251. package/dist/package.cjs.map +1 -1
  252. package/dist/package.js +1 -1
  253. package/dist/package.js.map +1 -1
  254. package/dist/routes/files-tab.cjs +1 -1
  255. package/dist/routes/files-tab.js +10 -10
  256. package/dist/types/automation.d.ts +8 -0
  257. package/dist/utils/custom-toast-handlers.cjs.map +1 -1
  258. package/dist/utils/custom-toast-handlers.d.ts +1 -0
  259. package/dist/utils/custom-toast-handlers.js.map +1 -1
  260. package/dist/utils/mcp-server-name.cjs +1 -1
  261. package/dist/utils/mcp-server-name.cjs.map +1 -1
  262. package/dist/utils/mcp-server-name.js +2 -2
  263. package/dist/utils/mcp-server-name.js.map +1 -1
  264. package/dist/utils/transcript-export/index.cjs +72 -0
  265. package/dist/utils/transcript-export/index.cjs.map +1 -0
  266. package/dist/utils/transcript-export/index.d.ts +10 -0
  267. package/dist/utils/transcript-export/index.js +302 -0
  268. package/dist/utils/transcript-export/index.js.map +1 -0
  269. package/dist/utils/transcript-export/load-complete-events.cjs +2 -0
  270. package/dist/utils/transcript-export/load-complete-events.cjs.map +1 -0
  271. package/dist/utils/transcript-export/load-complete-events.d.ts +22 -0
  272. package/dist/utils/transcript-export/load-complete-events.js +39 -0
  273. package/dist/utils/transcript-export/load-complete-events.js.map +1 -0
  274. package/package.json +1 -1
  275. package/scripts/check-sdk-version-sync.mjs +6 -6
  276. package/scripts/dev-safe.mjs +2 -2
  277. package/build/assets/active-backend-context-u2tdYRgH.js +0 -1
  278. package/build/assets/agent-settings-FGL3Yvkp.js +0 -1
  279. package/build/assets/automation-detail-DwYGzLkp.js +0 -2
  280. package/build/assets/automations-list-CuAfJmMW.js +0 -1
  281. package/build/assets/conversation-DnVC6vRV.js +0 -1
  282. package/build/assets/conversation-panel-ZEz-z3az.js +0 -1
  283. package/build/assets/conversation-xkBS3AHC.js +0 -19
  284. package/build/assets/declaration-B9kpCaYl.js +0 -1
  285. package/build/assets/edit-automation-modal-B6U96gVV.js +0 -1
  286. package/build/assets/files-tab-61Vaihc6.js +0 -1
  287. package/build/assets/home-5gOtUe-n.js +0 -1
  288. package/build/assets/lesson-plan-BtrZUCuj.js +0 -4
  289. package/build/assets/llm-settings-DsInf6yD.js +0 -1
  290. package/build/assets/manifest-a5bb7568.js +0 -1
  291. package/build/assets/onboarding-D32kiGME.js +0 -1
  292. package/build/assets/providers-vX9jk9Vy.js +0 -1
  293. package/build/assets/root-CxWZUXTQ.css +0 -1
  294. package/build/assets/root-layout-CoWw4kpz.js +0 -2
  295. package/build/assets/settings-service.api-DldkFI1x.js +0 -1
  296. package/build/assets/use-runtime-is-ready-Diiq65Q-.js +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/utils/transcript-export/index.ts"],"sourcesContent":["import type {\n ActionEvent,\n OpenHandsEvent,\n ObservationEvent,\n} from \"#/types/agent-server/core\";\nimport type { TaskAction } from \"#/types/agent-server/core/base/action\";\nimport type { TaskObservation } from \"#/types/agent-server/core/base/observation\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isAgentErrorEvent,\n isConversationStateUpdateEvent,\n isGoalConversationStateUpdateEvent,\n isHookExecutionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n isSwitchLLMObservationEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { handleEventForUI } from \"#/utils/handle-event-for-ui\";\nimport { shouldRenderEvent } from \"#/components/conversation-events/chat/event-content-helpers/should-render-event\";\nimport { parseMessageFromEvent } from \"#/components/conversation-events/chat/event-content-helpers/parse-message-from-event\";\nimport { getActionContent } from \"#/components/conversation-events/chat/event-content-helpers/get-action-content\";\nimport { getObservationContent } from \"#/components/conversation-events/chat/event-content-helpers/get-observation-content\";\nimport {\n getACPToolCallContent,\n stripRedundantTitlePrefix,\n} from \"#/components/conversation-events/chat/event-content-helpers/get-acp-tool-call-content\";\nimport { groupEvents } from \"#/components/conversation-events/chat/group-events\";\nimport {\n getActionThoughtText,\n getReasoningContent,\n splitInlineThink,\n} from \"#/components/conversation-events/chat/event-thought-helpers\";\nimport i18n from \"#/i18n\";\nimport { I18nKey } from \"#/i18n/declaration\";\n\nexport type TranscriptExportFormat = \"markdown\" | \"html\";\n\nexport interface TranscriptExportOptions {\n includeToolDetails: boolean;\n includeTimestamps: boolean;\n title?: string | null;\n model?: string | null;\n}\n\ntype TranscriptEntry =\n | {\n kind: \"message\";\n author: \"user\" | \"assistant\";\n content: string;\n timestamp: string;\n }\n | {\n kind: \"tool\";\n summary: string;\n details: string;\n timestamp: string;\n }\n | {\n kind: \"error\";\n content: string;\n timestamp: string;\n }\n | {\n kind: \"note\";\n summary: string;\n content: string;\n timestamp: string;\n };\n\nconst SAFE_ACTION_DETAIL_KINDS = new Set([\n \"BrowserClickAction\",\n \"BrowserCloseTabAction\",\n \"BrowserGetContentAction\",\n \"BrowserGetStateAction\",\n \"BrowserGoBackAction\",\n \"BrowserListTabsAction\",\n \"BrowserNavigateAction\",\n \"BrowserScrollAction\",\n \"BrowserSwitchTabAction\",\n \"BrowserTypeAction\",\n \"ExecuteBashAction\",\n \"FileEditorAction\",\n \"GlobAction\",\n \"GrepAction\",\n \"InvokeSkillAction\",\n \"MCPToolAction\",\n \"StrReplaceEditorAction\",\n \"TaskAction\",\n \"TaskTrackerAction\",\n \"TerminalAction\",\n \"ThinkAction\",\n]);\n\nconst SAFE_OBSERVATION_DETAIL_KINDS = new Set([\n \"BrowserObservation\",\n \"CanvasUIObservation\",\n \"ExecuteBashObservation\",\n \"FileEditorObservation\",\n \"GlobObservation\",\n \"GrepObservation\",\n \"InvokeSkillObservation\",\n \"MCPToolObservation\",\n \"StrReplaceEditorObservation\",\n \"SwitchLLMObservation\",\n \"TaskTrackerObservation\",\n \"TaskObservation\",\n \"TerminalObservation\",\n]);\n\nconst cleanInlineText = (value: string): string =>\n value\n .replace(/[\\r\\n]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n\nconst truncate = (value: string, maxLength = 100): string =>\n value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;\n\nconst formatTimestamp = (timestamp: string): string => {\n const date = new Date(timestamp);\n return Number.isNaN(date.getTime()) ? timestamp : date.toISOString();\n};\n\nconst escapeHtml = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n\n/**\n * GitHub Markdown permits raw HTML, so dynamic conversation text needs the\n * same inert representation as the chat's sanitized Markdown renderer.\n */\nconst sanitizeMarkdownText = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replace(\n /(!?)\\[([^\\]]*)\\]\\(\\s*((?:javascript|data|vbscript):[^)]*)\\)/gi,\n \"$1\\\\[$2\\\\]($3)\",\n )\n .replace(\n /^(\\s{0,3})\\[([^\\]]+)\\]:(\\s*<?(?:javascript|data|vbscript):)/gim,\n \"$1\\\\[$2\\\\]:$3\",\n );\n\nconst safeTitle = (title?: string | null): string =>\n cleanInlineText(title || i18n.t(I18nKey.TRANSCRIPT_EXPORT$DEFAULT_TITLE)) ||\n i18n.t(I18nKey.TRANSCRIPT_EXPORT$DEFAULT_TITLE);\n\nconst translatePlain = (\n key: I18nKey,\n values?: Record<string, unknown>,\n): string =>\n cleanInlineText(i18n.t(key, values).replace(/<\\/?(?:cmd|path)>/g, \"\"));\n\nconst isServerFallbackSummary = (summary: string): boolean =>\n /^[a-z][a-z0-9_]*\\s*:\\s*[[{]/i.test(summary);\n\nconst humanizeEventKind = (kind: string): string =>\n kind\n .replace(/(?:Action|Observation)$/, \"\")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .trim();\n\nconst getActionSummary = (event: ActionEvent): string => {\n const summary = cleanInlineText(event.summary || \"\");\n if (summary && !isServerFallbackSummary(summary)) return summary;\n return (\n cleanInlineText(event.tool_name) || humanizeEventKind(event.action.kind)\n );\n};\n\nconst getObservationSummary = (\n event: ObservationEvent,\n correspondingAction?: ActionEvent,\n): string => {\n if (correspondingAction) return getActionSummary(correspondingAction);\n return (\n cleanInlineText(event.tool_name) ||\n humanizeEventKind(event.observation.kind)\n );\n};\n\nconst getTextContent = (\n content: Array<{ type: string; text?: string }>,\n): string =>\n content\n .filter(\n (item): item is { type: \"text\"; text: string } =>\n item.type === \"text\" && typeof item.text === \"string\",\n )\n .map((item) => item.text)\n .join(\"\\n\");\n\nconst getTaskActionDetails = (action: TaskAction): string =>\n [\n `${i18n.t(I18nKey.TASK$SUBAGENT)}: ${action.subagent_type}`,\n `${i18n.t(I18nKey.TASK$QUERY)}:\\n${action.prompt}`,\n ].join(\"\\n\\n\");\n\nconst getTaskObservationDetails = (\n observation: TaskObservation,\n correspondingAction?: ActionEvent,\n): string => {\n const taskAction =\n correspondingAction?.action.kind === \"TaskAction\"\n ? correspondingAction.action\n : undefined;\n return [\n `${i18n.t(I18nKey.TASK$SUBAGENT)}: ${observation.subagent}`,\n `${i18n.t(I18nKey.TASK$TASK_ID)}: ${observation.task_id}`,\n taskAction ? `${i18n.t(I18nKey.TASK$QUERY)}:\\n${taskAction.prompt}` : \"\",\n `${i18n.t(I18nKey.TASK$RESULT)}:\\n${getTextContent(observation.content)}`,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n};\n\nconst getSafeActionDetails = (event: ActionEvent): string => {\n if (event.action.kind === \"TaskAction\") {\n return getTaskActionDetails(event.action);\n }\n return SAFE_ACTION_DETAIL_KINDS.has(event.action.kind)\n ? getActionContent(event)\n : \"\";\n};\n\nconst getSafeObservationDetails = (\n event: ObservationEvent,\n correspondingAction?: ActionEvent,\n): string => {\n if (event.observation.kind === \"TaskObservation\") {\n return getTaskObservationDetails(event.observation, correspondingAction);\n }\n return SAFE_OBSERVATION_DETAIL_KINDS.has(event.observation.kind)\n ? getObservationContent(event)\n : \"\";\n};\n\nconst getHookDetails = (event: OpenHandsEvent): string => {\n if (!isHookExecutionEvent(event)) return \"\";\n return [event.reason, event.error, event.stdout, event.stderr]\n .filter((value): value is string => Boolean(value?.trim()))\n .join(\"\\n\\n\");\n};\n\nconst getActionNarration = (event: ActionEvent): string =>\n [getReasoningContent(event), getActionThoughtText(event)]\n .map((content) => content.trim())\n .filter(Boolean)\n .join(\"\\n\\n\");\n\nconst canRenderActionNarration = (event: ActionEvent): boolean =>\n ![\"FinishAction\", \"SwitchLLMAction\", \"ThinkAction\"].includes(\n event.action.kind,\n );\n\nconst buildTranscriptEntries = (\n events: OpenHandsEvent[],\n includeToolDetails: boolean,\n): TranscriptEntry[] => {\n const uiEvents = events.reduce<OpenHandsEvent[]>((current, event) => {\n try {\n return handleEventForUI(event, current);\n } catch {\n return current;\n }\n }, []);\n const actionsById = new Map(\n events.filter(isActionEvent).map((event) => [event.id, event]),\n );\n const entries: TranscriptEntry[] = [];\n const emittedNarrationActionIds = new Set<string>();\n const renderableEvents = uiEvents.filter(\n (event) =>\n (isSwitchLLMObservationEvent(event) && !event.observation.is_error) ||\n shouldRenderEvent(event),\n );\n const renderedItems = groupEvents(\n renderableEvents,\n Number.MAX_SAFE_INTEGER,\n events,\n );\n\n const addActionNarration = (action: ActionEvent) => {\n if (\n emittedNarrationActionIds.has(action.id) ||\n !canRenderActionNarration(action)\n ) {\n return;\n }\n emittedNarrationActionIds.add(action.id);\n const content = getActionNarration(action);\n if (content) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content,\n timestamp: action.timestamp,\n });\n }\n };\n\n for (const item of renderedItems) {\n if (item.kind === \"group\") continue;\n if (item.kind === \"thought\") {\n addActionNarration(item.action);\n continue;\n }\n\n const { event } = item;\n try {\n const narrationAction = isActionEvent(event)\n ? event\n : isObservationEvent(event)\n ? actionsById.get(event.action_id)\n : undefined;\n if (narrationAction) addActionNarration(narrationAction);\n\n if (isSwitchLLMObservationEvent(event) && !event.observation.is_error) {\n entries.push({\n kind: \"note\",\n summary: translatePlain(I18nKey.MODEL$SWITCHED_TO_PROFILE, {\n name: event.observation.profile_name,\n }),\n content: [\n event.observation.active_model\n ? `${i18n.t(I18nKey.TRANSCRIPT_EXPORT$MODEL)}: ${event.observation.active_model}`\n : \"\",\n event.observation.reason\n ? `${i18n.t(I18nKey.TRANSCRIPT_EXPORT$REASON)}: ${event.observation.reason}`\n : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isMessageEvent(event)) {\n const parsed = parseMessageFromEvent(event).trim();\n if (event.source === \"agent\") {\n const { reasoning, message } = splitInlineThink(parsed);\n [reasoning, message].filter(Boolean).forEach((content) => {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content,\n timestamp: event.timestamp,\n });\n });\n } else if (parsed) {\n entries.push({\n kind: \"message\",\n author: \"user\",\n content: parsed,\n timestamp: event.timestamp,\n });\n }\n continue;\n }\n\n if (isStreamingDeltaEvent(event)) {\n const { reasoning: inlineThink, message } = splitInlineThink(\n event.content ?? \"\",\n { streaming: true },\n );\n const reasoningContent = [\n event.reasoning_content?.trim() || \"\",\n inlineThink,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n if (reasoningContent) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content: reasoningContent,\n timestamp: event.timestamp,\n });\n }\n if (message.trim()) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content: message.trim(),\n timestamp: event.timestamp,\n });\n }\n continue;\n }\n\n if (isAgentErrorEvent(event)) {\n entries.push({\n kind: \"error\",\n content: event.error,\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isActionEvent(event)) {\n if (event.action.kind === \"FinishAction\") {\n const content = event.action.message.trim();\n if (content) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content,\n timestamp: event.timestamp,\n });\n }\n } else {\n entries.push({\n kind: \"tool\",\n summary: getActionSummary(event),\n details: includeToolDetails ? getSafeActionDetails(event) : \"\",\n timestamp: event.timestamp,\n });\n }\n continue;\n }\n\n if (isObservationEvent(event)) {\n const correspondingAction = actionsById.get(event.action_id);\n entries.push({\n kind: \"tool\",\n summary: getObservationSummary(event, correspondingAction),\n details: includeToolDetails\n ? getSafeObservationDetails(event, correspondingAction)\n : \"\",\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isACPToolCallEvent(event)) {\n entries.push({\n kind: \"tool\",\n summary:\n stripRedundantTitlePrefix(event) ||\n i18n.t(I18nKey.ACTION_MESSAGE$ACP_TOOL),\n details: includeToolDetails ? getACPToolCallContent(event) : \"\",\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isHookExecutionEvent(event)) {\n entries.push({\n kind: \"tool\",\n summary: i18n.t(I18nKey.TRANSCRIPT_EXPORT$HOOK, {\n command: truncate(cleanInlineText(event.hook_command), 100),\n }),\n details: includeToolDetails ? getHookDetails(event) : \"\",\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (\n isConversationStateUpdateEvent(event) &&\n isGoalConversationStateUpdateEvent(event)\n ) {\n entries.push({\n kind: \"note\",\n summary: `${i18n.t(I18nKey.GOAL$PREFIX)} ${i18n.t(\n {\n running: I18nKey.GOAL$STATUS_RUNNING,\n complete: I18nKey.GOAL$STATUS_COMPLETE,\n capped: I18nKey.GOAL$STATUS_CAPPED,\n interrupted: I18nKey.GOAL$STATUS_INTERRUPTED,\n }[event.value.status],\n )}`,\n content: [event.value.objective, event.value.verdict?.missing || \"\"]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n timestamp: event.timestamp,\n });\n }\n } catch {\n // Runtime event payloads may be older than the local TypeScript schema.\n // Skip malformed entries instead of aborting an otherwise valid export.\n }\n }\n\n return entries;\n};\n\nconst markdownTimestamp = (\n entry: TranscriptEntry,\n options: TranscriptExportOptions,\n): string =>\n options.includeTimestamps\n ? `<sub>${escapeHtml(formatTimestamp(entry.timestamp))}</sub>\\n\\n`\n : \"\";\n\nconst markdownFence = (content: string): string => {\n const longestRun = Math.max(\n 0,\n ...Array.from(content.matchAll(/`+/g), (match) => match[0].length),\n );\n const fence = \"`\".repeat(Math.max(3, longestRun + 1));\n return `${fence}text\\n${content}\\n${fence}`;\n};\n\nexport const eventsToMarkdown = (\n events: OpenHandsEvent[],\n options: TranscriptExportOptions,\n): string => {\n const lines = [`# ${sanitizeMarkdownText(safeTitle(options.title))}`, \"\"];\n\n if (options.model) {\n lines.push(\n `**${i18n.t(I18nKey.TRANSCRIPT_EXPORT$MODEL)}:** ${sanitizeMarkdownText(cleanInlineText(options.model))}`,\n \"\",\n );\n }\n\n for (const entry of buildTranscriptEntries(\n events,\n options.includeToolDetails,\n )) {\n const timestamp = markdownTimestamp(entry, options);\n if (entry.kind === \"message\") {\n const author =\n entry.author === \"user\"\n ? i18n.t(I18nKey.TRANSCRIPT_EXPORT$USER)\n : i18n.t(I18nKey.CHAT_INTERFACE$ASSISTANT);\n lines.push(\n `## ${author}`,\n \"\",\n timestamp + sanitizeMarkdownText(entry.content),\n \"\",\n );\n } else if (entry.kind === \"error\") {\n const quoted = entry.content\n .split(\"\\n\")\n .map((line) => `> ${sanitizeMarkdownText(line)}`)\n .join(\"\\n\");\n lines.push(\n `## ${i18n.t(I18nKey.COMMON$ERROR)}`,\n \"\",\n timestamp + quoted,\n \"\",\n );\n } else if (entry.kind === \"note\") {\n lines.push(\n `> **${escapeHtml(entry.summary)}**`,\n \"\",\n timestamp + sanitizeMarkdownText(entry.content),\n \"\",\n );\n } else if (options.includeToolDetails && entry.details) {\n lines.push(\n \"<details>\",\n `<summary><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}</summary>`,\n \"\",\n timestamp + markdownFence(entry.details),\n \"\",\n \"</details>\",\n \"\",\n );\n } else {\n const timestampMarkup = timestamp ? `<br>${timestamp.trimEnd()}` : \"\";\n lines.push(\n `<p><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}${timestampMarkup}</p>`,\n \"\",\n );\n }\n }\n\n return `${lines.join(\"\\n\").trim()}\\n`;\n};\n\nconst htmlTimestamp = (\n entry: TranscriptEntry,\n options: TranscriptExportOptions,\n): string => {\n if (!options.includeTimestamps) return \"\";\n const timestamp = formatTimestamp(entry.timestamp);\n return `<time datetime=\"${escapeHtml(timestamp)}\">${escapeHtml(timestamp)}</time>`;\n};\n\nexport const eventsToHtml = (\n events: OpenHandsEvent[],\n options: TranscriptExportOptions,\n): string => {\n const title = safeTitle(options.title);\n const body = buildTranscriptEntries(events, options.includeToolDetails)\n .map((entry) => {\n const timestamp = htmlTimestamp(entry, options);\n if (entry.kind === \"message\") {\n const author =\n entry.author === \"user\"\n ? i18n.t(I18nKey.TRANSCRIPT_EXPORT$USER)\n : i18n.t(I18nKey.CHAT_INTERFACE$ASSISTANT);\n return `<section class=\"message ${entry.author.toLowerCase()}\">\n <header><h2>${escapeHtml(author)}</h2>${timestamp}</header>\n <div class=\"content\">${escapeHtml(entry.content)}</div>\n</section>`;\n }\n if (entry.kind === \"error\") {\n return `<section class=\"message error\">\n <header><h2>${escapeHtml(i18n.t(I18nKey.COMMON$ERROR))}</h2>${timestamp}</header>\n <div class=\"content\">${escapeHtml(entry.content)}</div>\n</section>`;\n }\n if (entry.kind === \"note\") {\n return `<aside class=\"note\">\n <header><strong>${escapeHtml(entry.summary)}</strong>${timestamp}</header>\n ${entry.content ? `<div class=\"content\">${escapeHtml(entry.content)}</div>` : \"\"}\n</aside>`;\n }\n const details =\n options.includeToolDetails && entry.details\n ? `<details>\n <summary><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}${timestamp}</summary>\n <pre>${escapeHtml(entry.details)}</pre>\n</details>`\n : `<div class=\"tool-summary\"><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}${timestamp}</div>`;\n return details;\n })\n .join(\"\\n\");\n\n const model = options.model\n ? `<p class=\"model\"><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$MODEL))}:</strong> ${escapeHtml(cleanInlineText(options.model))}</p>`\n : \"\";\n\n return `<!doctype html>\n<html lang=\"${escapeHtml(i18n.resolvedLanguage || i18n.language || \"en\")}\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; img-src data:\">\n <title>${escapeHtml(title)}</title>\n <style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, sans-serif; }\n body { margin: 0; background: #111827; color: #e5e7eb; line-height: 1.55; }\n main { box-sizing: border-box; width: min(860px, 100%); margin: 0 auto; padding: 48px 24px 80px; }\n h1 { margin: 0; font-size: 2rem; }\n h2 { margin: 0; font-size: 1rem; }\n .model { margin: 8px 0 32px; color: #9ca3af; }\n .message, details, .tool-summary, .note { margin: 16px 0; border: 1px solid #374151; border-radius: 10px; padding: 16px; background: #1f2937; }\n .user { border-left: 4px solid #60a5fa; }\n .assistant { border-left: 4px solid #34d399; }\n .error { border-left: 4px solid #f87171; }\n .note { border-left: 4px solid #a78bfa; }\n header, summary, .tool-summary { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }\n summary { cursor: pointer; }\n time { flex: none; color: #9ca3af; font-size: .75rem; font-weight: 400; }\n .content { margin-top: 10px; white-space: pre-wrap; overflow-wrap: anywhere; }\n pre { margin: 14px 0 0; padding: 14px; overflow-x: auto; border-radius: 7px; background: #111827; color: #d1d5db; white-space: pre-wrap; overflow-wrap: anywhere; }\n @media (prefers-color-scheme: light) {\n body { background: #f9fafb; color: #111827; }\n .message, details, .tool-summary, .note { border-color: #d1d5db; background: #fff; }\n pre { background: #f3f4f6; color: #1f2937; }\n .model, time { color: #6b7280; }\n }\n </style>\n</head>\n<body>\n <main>\n <h1>${escapeHtml(title)}</h1>\n ${model}\n ${body}\n </main>\n</body>\n</html>\n`;\n};\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { OpenHandsEvent } from "#/types/agent-server/core";
2
+ export type TranscriptExportFormat = "markdown" | "html";
3
+ export interface TranscriptExportOptions {
4
+ includeToolDetails: boolean;
5
+ includeTimestamps: boolean;
6
+ title?: string | null;
7
+ model?: string | null;
8
+ }
9
+ export declare const eventsToMarkdown: (events: OpenHandsEvent[], options: TranscriptExportOptions) => string;
10
+ export declare const eventsToHtml: (events: OpenHandsEvent[], options: TranscriptExportOptions) => string;
@@ -0,0 +1,302 @@
1
+ import { I18nKey as e } from "../../i18n/declaration.js";
2
+ import t from "../../i18n/index.js";
3
+ import { isACPToolCallEvent as n, isActionEvent as r, isAgentErrorEvent as i, isConversationStateUpdateEvent as a, isGoalConversationStateUpdateEvent as o, isHookExecutionEvent as s, isMessageEvent as c, isObservationEvent as l, isStreamingDeltaEvent as u, isSwitchLLMObservationEvent as d } from "../../types/agent-server/type-guards.js";
4
+ import { getActionThoughtText as f, getReasoningContent as p, splitInlineThink as m } from "../../components/conversation-events/chat/event-thought-helpers.js";
5
+ import { handleEventForUI as h } from "../handle-event-for-ui.js";
6
+ import { shouldRenderEvent as g } from "../../components/conversation-events/chat/event-content-helpers/should-render-event.js";
7
+ import { parseMessageFromEvent as _ } from "../../components/conversation-events/chat/event-content-helpers/parse-message-from-event.js";
8
+ import { getActionContent as v } from "../../components/conversation-events/chat/event-content-helpers/get-action-content.js";
9
+ import { getObservationContent as y } from "../../components/conversation-events/chat/event-content-helpers/get-observation-content.js";
10
+ import { getACPToolCallContent as b, stripRedundantTitlePrefix as x } from "../../components/conversation-events/chat/event-content-helpers/get-acp-tool-call-content.js";
11
+ import { groupEvents as S } from "../../components/conversation-events/chat/group-events.js";
12
+ //#region src/utils/transcript-export/index.ts
13
+ var C = new Set([
14
+ "BrowserClickAction",
15
+ "BrowserCloseTabAction",
16
+ "BrowserGetContentAction",
17
+ "BrowserGetStateAction",
18
+ "BrowserGoBackAction",
19
+ "BrowserListTabsAction",
20
+ "BrowserNavigateAction",
21
+ "BrowserScrollAction",
22
+ "BrowserSwitchTabAction",
23
+ "BrowserTypeAction",
24
+ "ExecuteBashAction",
25
+ "FileEditorAction",
26
+ "GlobAction",
27
+ "GrepAction",
28
+ "InvokeSkillAction",
29
+ "MCPToolAction",
30
+ "StrReplaceEditorAction",
31
+ "TaskAction",
32
+ "TaskTrackerAction",
33
+ "TerminalAction",
34
+ "ThinkAction"
35
+ ]), w = new Set([
36
+ "BrowserObservation",
37
+ "CanvasUIObservation",
38
+ "ExecuteBashObservation",
39
+ "FileEditorObservation",
40
+ "GlobObservation",
41
+ "GrepObservation",
42
+ "InvokeSkillObservation",
43
+ "MCPToolObservation",
44
+ "StrReplaceEditorObservation",
45
+ "SwitchLLMObservation",
46
+ "TaskTrackerObservation",
47
+ "TaskObservation",
48
+ "TerminalObservation"
49
+ ]), T = (e) => e.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim(), E = (e, t = 100) => e.length > t ? `${e.slice(0, t)}…` : e, D = (e) => {
50
+ let t = new Date(e);
51
+ return Number.isNaN(t.getTime()) ? e : t.toISOString();
52
+ }, O = (e) => e.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#039;"), k = (e) => e.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replace(/(!?)\[([^\]]*)\]\(\s*((?:javascript|data|vbscript):[^)]*)\)/gi, "$1\\[$2\\]($3)").replace(/^(\s{0,3})\[([^\]]+)\]:(\s*<?(?:javascript|data|vbscript):)/gim, "$1\\[$2\\]:$3"), A = (n) => T(n || t.t(e.TRANSCRIPT_EXPORT$DEFAULT_TITLE)) || t.t(e.TRANSCRIPT_EXPORT$DEFAULT_TITLE), j = (e, n) => T(t.t(e, n).replace(/<\/?(?:cmd|path)>/g, "")), M = (e) => /^[a-z][a-z0-9_]*\s*:\s*[[{]/i.test(e), N = (e) => e.replace(/(?:Action|Observation)$/, "").replace(/([a-z])([A-Z])/g, "$1 $2").trim(), P = (e) => {
53
+ let t = T(e.summary || "");
54
+ return t && !M(t) ? t : T(e.tool_name) || N(e.action.kind);
55
+ }, F = (e, t) => t ? P(t) : T(e.tool_name) || N(e.observation.kind), I = (e) => e.filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text).join("\n"), L = (n) => [`${t.t(e.TASK$SUBAGENT)}: ${n.subagent_type}`, `${t.t(e.TASK$QUERY)}:\n${n.prompt}`].join("\n\n"), R = (n, r) => {
56
+ let i = r?.action.kind === "TaskAction" ? r.action : void 0;
57
+ return [
58
+ `${t.t(e.TASK$SUBAGENT)}: ${n.subagent}`,
59
+ `${t.t(e.TASK$TASK_ID)}: ${n.task_id}`,
60
+ i ? `${t.t(e.TASK$QUERY)}:\n${i.prompt}` : "",
61
+ `${t.t(e.TASK$RESULT)}:\n${I(n.content)}`
62
+ ].filter(Boolean).join("\n\n");
63
+ }, z = (e) => e.action.kind === "TaskAction" ? L(e.action) : C.has(e.action.kind) ? v(e) : "", B = (e, t) => e.observation.kind === "TaskObservation" ? R(e.observation, t) : w.has(e.observation.kind) ? y(e) : "", V = (e) => s(e) ? [
64
+ e.reason,
65
+ e.error,
66
+ e.stdout,
67
+ e.stderr
68
+ ].filter((e) => !!e?.trim()).join("\n\n") : "", H = (e) => [p(e), f(e)].map((e) => e.trim()).filter(Boolean).join("\n\n"), U = (e) => ![
69
+ "FinishAction",
70
+ "SwitchLLMAction",
71
+ "ThinkAction"
72
+ ].includes(e.action.kind), W = (f, p) => {
73
+ let v = f.reduce((e, t) => {
74
+ try {
75
+ return h(t, e);
76
+ } catch {
77
+ return e;
78
+ }
79
+ }, []), y = new Map(f.filter(r).map((e) => [e.id, e])), C = [], w = /* @__PURE__ */ new Set(), D = S(v.filter((e) => d(e) && !e.observation.is_error || g(e)), 2 ** 53 - 1, f), O = (e) => {
80
+ if (w.has(e.id) || !U(e)) return;
81
+ w.add(e.id);
82
+ let t = H(e);
83
+ t && C.push({
84
+ kind: "message",
85
+ author: "assistant",
86
+ content: t,
87
+ timestamp: e.timestamp
88
+ });
89
+ };
90
+ for (let f of D) {
91
+ if (f.kind === "group") continue;
92
+ if (f.kind === "thought") {
93
+ O(f.action);
94
+ continue;
95
+ }
96
+ let { event: h } = f;
97
+ try {
98
+ let f = r(h) ? h : l(h) ? y.get(h.action_id) : void 0;
99
+ if (f && O(f), d(h) && !h.observation.is_error) {
100
+ C.push({
101
+ kind: "note",
102
+ summary: j(e.MODEL$SWITCHED_TO_PROFILE, { name: h.observation.profile_name }),
103
+ content: [h.observation.active_model ? `${t.t(e.TRANSCRIPT_EXPORT$MODEL)}: ${h.observation.active_model}` : "", h.observation.reason ? `${t.t(e.TRANSCRIPT_EXPORT$REASON)}: ${h.observation.reason}` : ""].filter(Boolean).join("\n"),
104
+ timestamp: h.timestamp
105
+ });
106
+ continue;
107
+ }
108
+ if (c(h)) {
109
+ let e = _(h).trim();
110
+ if (h.source === "agent") {
111
+ let { reasoning: t, message: n } = m(e);
112
+ [t, n].filter(Boolean).forEach((e) => {
113
+ C.push({
114
+ kind: "message",
115
+ author: "assistant",
116
+ content: e,
117
+ timestamp: h.timestamp
118
+ });
119
+ });
120
+ } else e && C.push({
121
+ kind: "message",
122
+ author: "user",
123
+ content: e,
124
+ timestamp: h.timestamp
125
+ });
126
+ continue;
127
+ }
128
+ if (u(h)) {
129
+ let { reasoning: e, message: t } = m(h.content ?? "", { streaming: !0 }), n = [h.reasoning_content?.trim() || "", e].filter(Boolean).join("\n\n");
130
+ n && C.push({
131
+ kind: "message",
132
+ author: "assistant",
133
+ content: n,
134
+ timestamp: h.timestamp
135
+ }), t.trim() && C.push({
136
+ kind: "message",
137
+ author: "assistant",
138
+ content: t.trim(),
139
+ timestamp: h.timestamp
140
+ });
141
+ continue;
142
+ }
143
+ if (i(h)) {
144
+ C.push({
145
+ kind: "error",
146
+ content: h.error,
147
+ timestamp: h.timestamp
148
+ });
149
+ continue;
150
+ }
151
+ if (r(h)) {
152
+ if (h.action.kind === "FinishAction") {
153
+ let e = h.action.message.trim();
154
+ e && C.push({
155
+ kind: "message",
156
+ author: "assistant",
157
+ content: e,
158
+ timestamp: h.timestamp
159
+ });
160
+ } else C.push({
161
+ kind: "tool",
162
+ summary: P(h),
163
+ details: p ? z(h) : "",
164
+ timestamp: h.timestamp
165
+ });
166
+ continue;
167
+ }
168
+ if (l(h)) {
169
+ let e = y.get(h.action_id);
170
+ C.push({
171
+ kind: "tool",
172
+ summary: F(h, e),
173
+ details: p ? B(h, e) : "",
174
+ timestamp: h.timestamp
175
+ });
176
+ continue;
177
+ }
178
+ if (n(h)) {
179
+ C.push({
180
+ kind: "tool",
181
+ summary: x(h) || t.t(e.ACTION_MESSAGE$ACP_TOOL),
182
+ details: p ? b(h) : "",
183
+ timestamp: h.timestamp
184
+ });
185
+ continue;
186
+ }
187
+ if (s(h)) {
188
+ C.push({
189
+ kind: "tool",
190
+ summary: t.t(e.TRANSCRIPT_EXPORT$HOOK, { command: E(T(h.hook_command), 100) }),
191
+ details: p ? V(h) : "",
192
+ timestamp: h.timestamp
193
+ });
194
+ continue;
195
+ }
196
+ a(h) && o(h) && C.push({
197
+ kind: "note",
198
+ summary: `${t.t(e.GOAL$PREFIX)} ${t.t({
199
+ running: e.GOAL$STATUS_RUNNING,
200
+ complete: e.GOAL$STATUS_COMPLETE,
201
+ capped: e.GOAL$STATUS_CAPPED,
202
+ interrupted: e.GOAL$STATUS_INTERRUPTED
203
+ }[h.value.status])}`,
204
+ content: [h.value.objective, h.value.verdict?.missing || ""].filter(Boolean).join("\n\n"),
205
+ timestamp: h.timestamp
206
+ });
207
+ } catch {}
208
+ }
209
+ return C;
210
+ }, G = (e, t) => t.includeTimestamps ? `<sub>${O(D(e.timestamp))}</sub>\n\n` : "", K = (e) => {
211
+ let t = Math.max(0, ...Array.from(e.matchAll(/`+/g), (e) => e[0].length)), n = "`".repeat(Math.max(3, t + 1));
212
+ return `${n}text\n${e}\n${n}`;
213
+ }, q = (n, r) => {
214
+ let i = [`# ${k(A(r.title))}`, ""];
215
+ r.model && i.push(`**${t.t(e.TRANSCRIPT_EXPORT$MODEL)}:** ${k(T(r.model))}`, "");
216
+ for (let a of W(n, r.includeToolDetails)) {
217
+ let n = G(a, r);
218
+ if (a.kind === "message") {
219
+ let r = a.author === "user" ? t.t(e.TRANSCRIPT_EXPORT$USER) : t.t(e.CHAT_INTERFACE$ASSISTANT);
220
+ i.push(`## ${r}`, "", n + k(a.content), "");
221
+ } else if (a.kind === "error") {
222
+ let r = a.content.split("\n").map((e) => `> ${k(e)}`).join("\n");
223
+ i.push(`## ${t.t(e.COMMON$ERROR)}`, "", n + r, "");
224
+ } else if (a.kind === "note") i.push(`> **${O(a.summary)}**`, "", n + k(a.content), "");
225
+ else if (r.includeToolDetails && a.details) i.push("<details>", `<summary><strong>${O(t.t(e.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${O(a.summary)}</summary>`, "", n + K(a.details), "", "</details>", "");
226
+ else {
227
+ let r = n ? `<br>${n.trimEnd()}` : "";
228
+ i.push(`<p><strong>${O(t.t(e.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${O(a.summary)}${r}</p>`, "");
229
+ }
230
+ }
231
+ return `${i.join("\n").trim()}\n`;
232
+ }, J = (e, t) => {
233
+ if (!t.includeTimestamps) return "";
234
+ let n = D(e.timestamp);
235
+ return `<time datetime="${O(n)}">${O(n)}</time>`;
236
+ }, Y = (n, r) => {
237
+ let i = A(r.title), a = W(n, r.includeToolDetails).map((n) => {
238
+ let i = J(n, r);
239
+ if (n.kind === "message") {
240
+ let r = n.author === "user" ? t.t(e.TRANSCRIPT_EXPORT$USER) : t.t(e.CHAT_INTERFACE$ASSISTANT);
241
+ return `<section class="message ${n.author.toLowerCase()}">
242
+ <header><h2>${O(r)}</h2>${i}</header>
243
+ <div class="content">${O(n.content)}</div>
244
+ </section>`;
245
+ }
246
+ return n.kind === "error" ? `<section class="message error">
247
+ <header><h2>${O(t.t(e.COMMON$ERROR))}</h2>${i}</header>
248
+ <div class="content">${O(n.content)}</div>
249
+ </section>` : n.kind === "note" ? `<aside class="note">
250
+ <header><strong>${O(n.summary)}</strong>${i}</header>
251
+ ${n.content ? `<div class="content">${O(n.content)}</div>` : ""}
252
+ </aside>` : r.includeToolDetails && n.details ? `<details>
253
+ <summary><strong>${O(t.t(e.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${O(n.summary)}${i}</summary>
254
+ <pre>${O(n.details)}</pre>
255
+ </details>` : `<div class="tool-summary"><strong>${O(t.t(e.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${O(n.summary)}${i}</div>`;
256
+ }).join("\n"), o = r.model ? `<p class="model"><strong>${O(t.t(e.TRANSCRIPT_EXPORT$MODEL))}:</strong> ${O(T(r.model))}</p>` : "";
257
+ return `<!doctype html>
258
+ <html lang="${O(t.resolvedLanguage || t.language || "en")}">
259
+ <head>
260
+ <meta charset="utf-8">
261
+ <meta name="viewport" content="width=device-width, initial-scale=1">
262
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:">
263
+ <title>${O(i)}</title>
264
+ <style>
265
+ :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, sans-serif; }
266
+ body { margin: 0; background: #111827; color: #e5e7eb; line-height: 1.55; }
267
+ main { box-sizing: border-box; width: min(860px, 100%); margin: 0 auto; padding: 48px 24px 80px; }
268
+ h1 { margin: 0; font-size: 2rem; }
269
+ h2 { margin: 0; font-size: 1rem; }
270
+ .model { margin: 8px 0 32px; color: #9ca3af; }
271
+ .message, details, .tool-summary, .note { margin: 16px 0; border: 1px solid #374151; border-radius: 10px; padding: 16px; background: #1f2937; }
272
+ .user { border-left: 4px solid #60a5fa; }
273
+ .assistant { border-left: 4px solid #34d399; }
274
+ .error { border-left: 4px solid #f87171; }
275
+ .note { border-left: 4px solid #a78bfa; }
276
+ header, summary, .tool-summary { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
277
+ summary { cursor: pointer; }
278
+ time { flex: none; color: #9ca3af; font-size: .75rem; font-weight: 400; }
279
+ .content { margin-top: 10px; white-space: pre-wrap; overflow-wrap: anywhere; }
280
+ pre { margin: 14px 0 0; padding: 14px; overflow-x: auto; border-radius: 7px; background: #111827; color: #d1d5db; white-space: pre-wrap; overflow-wrap: anywhere; }
281
+ @media (prefers-color-scheme: light) {
282
+ body { background: #f9fafb; color: #111827; }
283
+ .message, details, .tool-summary, .note { border-color: #d1d5db; background: #fff; }
284
+ pre { background: #f3f4f6; color: #1f2937; }
285
+ .model, time { color: #6b7280; }
286
+ }
287
+ </style>
288
+ </head>
289
+ <body>
290
+ <main>
291
+ <h1>${O(i)}</h1>
292
+ ${o}
293
+ ${a}
294
+ </main>
295
+ </body>
296
+ </html>
297
+ `;
298
+ };
299
+ //#endregion
300
+ export { Y as eventsToHtml, q as eventsToMarkdown };
301
+
302
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/utils/transcript-export/index.ts"],"sourcesContent":["import type {\n ActionEvent,\n OpenHandsEvent,\n ObservationEvent,\n} from \"#/types/agent-server/core\";\nimport type { TaskAction } from \"#/types/agent-server/core/base/action\";\nimport type { TaskObservation } from \"#/types/agent-server/core/base/observation\";\nimport {\n isACPToolCallEvent,\n isActionEvent,\n isAgentErrorEvent,\n isConversationStateUpdateEvent,\n isGoalConversationStateUpdateEvent,\n isHookExecutionEvent,\n isMessageEvent,\n isObservationEvent,\n isStreamingDeltaEvent,\n isSwitchLLMObservationEvent,\n} from \"#/types/agent-server/type-guards\";\nimport { handleEventForUI } from \"#/utils/handle-event-for-ui\";\nimport { shouldRenderEvent } from \"#/components/conversation-events/chat/event-content-helpers/should-render-event\";\nimport { parseMessageFromEvent } from \"#/components/conversation-events/chat/event-content-helpers/parse-message-from-event\";\nimport { getActionContent } from \"#/components/conversation-events/chat/event-content-helpers/get-action-content\";\nimport { getObservationContent } from \"#/components/conversation-events/chat/event-content-helpers/get-observation-content\";\nimport {\n getACPToolCallContent,\n stripRedundantTitlePrefix,\n} from \"#/components/conversation-events/chat/event-content-helpers/get-acp-tool-call-content\";\nimport { groupEvents } from \"#/components/conversation-events/chat/group-events\";\nimport {\n getActionThoughtText,\n getReasoningContent,\n splitInlineThink,\n} from \"#/components/conversation-events/chat/event-thought-helpers\";\nimport i18n from \"#/i18n\";\nimport { I18nKey } from \"#/i18n/declaration\";\n\nexport type TranscriptExportFormat = \"markdown\" | \"html\";\n\nexport interface TranscriptExportOptions {\n includeToolDetails: boolean;\n includeTimestamps: boolean;\n title?: string | null;\n model?: string | null;\n}\n\ntype TranscriptEntry =\n | {\n kind: \"message\";\n author: \"user\" | \"assistant\";\n content: string;\n timestamp: string;\n }\n | {\n kind: \"tool\";\n summary: string;\n details: string;\n timestamp: string;\n }\n | {\n kind: \"error\";\n content: string;\n timestamp: string;\n }\n | {\n kind: \"note\";\n summary: string;\n content: string;\n timestamp: string;\n };\n\nconst SAFE_ACTION_DETAIL_KINDS = new Set([\n \"BrowserClickAction\",\n \"BrowserCloseTabAction\",\n \"BrowserGetContentAction\",\n \"BrowserGetStateAction\",\n \"BrowserGoBackAction\",\n \"BrowserListTabsAction\",\n \"BrowserNavigateAction\",\n \"BrowserScrollAction\",\n \"BrowserSwitchTabAction\",\n \"BrowserTypeAction\",\n \"ExecuteBashAction\",\n \"FileEditorAction\",\n \"GlobAction\",\n \"GrepAction\",\n \"InvokeSkillAction\",\n \"MCPToolAction\",\n \"StrReplaceEditorAction\",\n \"TaskAction\",\n \"TaskTrackerAction\",\n \"TerminalAction\",\n \"ThinkAction\",\n]);\n\nconst SAFE_OBSERVATION_DETAIL_KINDS = new Set([\n \"BrowserObservation\",\n \"CanvasUIObservation\",\n \"ExecuteBashObservation\",\n \"FileEditorObservation\",\n \"GlobObservation\",\n \"GrepObservation\",\n \"InvokeSkillObservation\",\n \"MCPToolObservation\",\n \"StrReplaceEditorObservation\",\n \"SwitchLLMObservation\",\n \"TaskTrackerObservation\",\n \"TaskObservation\",\n \"TerminalObservation\",\n]);\n\nconst cleanInlineText = (value: string): string =>\n value\n .replace(/[\\r\\n]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n\nconst truncate = (value: string, maxLength = 100): string =>\n value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;\n\nconst formatTimestamp = (timestamp: string): string => {\n const date = new Date(timestamp);\n return Number.isNaN(date.getTime()) ? timestamp : date.toISOString();\n};\n\nconst escapeHtml = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&#039;\");\n\n/**\n * GitHub Markdown permits raw HTML, so dynamic conversation text needs the\n * same inert representation as the chat's sanitized Markdown renderer.\n */\nconst sanitizeMarkdownText = (value: string): string =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replace(\n /(!?)\\[([^\\]]*)\\]\\(\\s*((?:javascript|data|vbscript):[^)]*)\\)/gi,\n \"$1\\\\[$2\\\\]($3)\",\n )\n .replace(\n /^(\\s{0,3})\\[([^\\]]+)\\]:(\\s*<?(?:javascript|data|vbscript):)/gim,\n \"$1\\\\[$2\\\\]:$3\",\n );\n\nconst safeTitle = (title?: string | null): string =>\n cleanInlineText(title || i18n.t(I18nKey.TRANSCRIPT_EXPORT$DEFAULT_TITLE)) ||\n i18n.t(I18nKey.TRANSCRIPT_EXPORT$DEFAULT_TITLE);\n\nconst translatePlain = (\n key: I18nKey,\n values?: Record<string, unknown>,\n): string =>\n cleanInlineText(i18n.t(key, values).replace(/<\\/?(?:cmd|path)>/g, \"\"));\n\nconst isServerFallbackSummary = (summary: string): boolean =>\n /^[a-z][a-z0-9_]*\\s*:\\s*[[{]/i.test(summary);\n\nconst humanizeEventKind = (kind: string): string =>\n kind\n .replace(/(?:Action|Observation)$/, \"\")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .trim();\n\nconst getActionSummary = (event: ActionEvent): string => {\n const summary = cleanInlineText(event.summary || \"\");\n if (summary && !isServerFallbackSummary(summary)) return summary;\n return (\n cleanInlineText(event.tool_name) || humanizeEventKind(event.action.kind)\n );\n};\n\nconst getObservationSummary = (\n event: ObservationEvent,\n correspondingAction?: ActionEvent,\n): string => {\n if (correspondingAction) return getActionSummary(correspondingAction);\n return (\n cleanInlineText(event.tool_name) ||\n humanizeEventKind(event.observation.kind)\n );\n};\n\nconst getTextContent = (\n content: Array<{ type: string; text?: string }>,\n): string =>\n content\n .filter(\n (item): item is { type: \"text\"; text: string } =>\n item.type === \"text\" && typeof item.text === \"string\",\n )\n .map((item) => item.text)\n .join(\"\\n\");\n\nconst getTaskActionDetails = (action: TaskAction): string =>\n [\n `${i18n.t(I18nKey.TASK$SUBAGENT)}: ${action.subagent_type}`,\n `${i18n.t(I18nKey.TASK$QUERY)}:\\n${action.prompt}`,\n ].join(\"\\n\\n\");\n\nconst getTaskObservationDetails = (\n observation: TaskObservation,\n correspondingAction?: ActionEvent,\n): string => {\n const taskAction =\n correspondingAction?.action.kind === \"TaskAction\"\n ? correspondingAction.action\n : undefined;\n return [\n `${i18n.t(I18nKey.TASK$SUBAGENT)}: ${observation.subagent}`,\n `${i18n.t(I18nKey.TASK$TASK_ID)}: ${observation.task_id}`,\n taskAction ? `${i18n.t(I18nKey.TASK$QUERY)}:\\n${taskAction.prompt}` : \"\",\n `${i18n.t(I18nKey.TASK$RESULT)}:\\n${getTextContent(observation.content)}`,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n};\n\nconst getSafeActionDetails = (event: ActionEvent): string => {\n if (event.action.kind === \"TaskAction\") {\n return getTaskActionDetails(event.action);\n }\n return SAFE_ACTION_DETAIL_KINDS.has(event.action.kind)\n ? getActionContent(event)\n : \"\";\n};\n\nconst getSafeObservationDetails = (\n event: ObservationEvent,\n correspondingAction?: ActionEvent,\n): string => {\n if (event.observation.kind === \"TaskObservation\") {\n return getTaskObservationDetails(event.observation, correspondingAction);\n }\n return SAFE_OBSERVATION_DETAIL_KINDS.has(event.observation.kind)\n ? getObservationContent(event)\n : \"\";\n};\n\nconst getHookDetails = (event: OpenHandsEvent): string => {\n if (!isHookExecutionEvent(event)) return \"\";\n return [event.reason, event.error, event.stdout, event.stderr]\n .filter((value): value is string => Boolean(value?.trim()))\n .join(\"\\n\\n\");\n};\n\nconst getActionNarration = (event: ActionEvent): string =>\n [getReasoningContent(event), getActionThoughtText(event)]\n .map((content) => content.trim())\n .filter(Boolean)\n .join(\"\\n\\n\");\n\nconst canRenderActionNarration = (event: ActionEvent): boolean =>\n ![\"FinishAction\", \"SwitchLLMAction\", \"ThinkAction\"].includes(\n event.action.kind,\n );\n\nconst buildTranscriptEntries = (\n events: OpenHandsEvent[],\n includeToolDetails: boolean,\n): TranscriptEntry[] => {\n const uiEvents = events.reduce<OpenHandsEvent[]>((current, event) => {\n try {\n return handleEventForUI(event, current);\n } catch {\n return current;\n }\n }, []);\n const actionsById = new Map(\n events.filter(isActionEvent).map((event) => [event.id, event]),\n );\n const entries: TranscriptEntry[] = [];\n const emittedNarrationActionIds = new Set<string>();\n const renderableEvents = uiEvents.filter(\n (event) =>\n (isSwitchLLMObservationEvent(event) && !event.observation.is_error) ||\n shouldRenderEvent(event),\n );\n const renderedItems = groupEvents(\n renderableEvents,\n Number.MAX_SAFE_INTEGER,\n events,\n );\n\n const addActionNarration = (action: ActionEvent) => {\n if (\n emittedNarrationActionIds.has(action.id) ||\n !canRenderActionNarration(action)\n ) {\n return;\n }\n emittedNarrationActionIds.add(action.id);\n const content = getActionNarration(action);\n if (content) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content,\n timestamp: action.timestamp,\n });\n }\n };\n\n for (const item of renderedItems) {\n if (item.kind === \"group\") continue;\n if (item.kind === \"thought\") {\n addActionNarration(item.action);\n continue;\n }\n\n const { event } = item;\n try {\n const narrationAction = isActionEvent(event)\n ? event\n : isObservationEvent(event)\n ? actionsById.get(event.action_id)\n : undefined;\n if (narrationAction) addActionNarration(narrationAction);\n\n if (isSwitchLLMObservationEvent(event) && !event.observation.is_error) {\n entries.push({\n kind: \"note\",\n summary: translatePlain(I18nKey.MODEL$SWITCHED_TO_PROFILE, {\n name: event.observation.profile_name,\n }),\n content: [\n event.observation.active_model\n ? `${i18n.t(I18nKey.TRANSCRIPT_EXPORT$MODEL)}: ${event.observation.active_model}`\n : \"\",\n event.observation.reason\n ? `${i18n.t(I18nKey.TRANSCRIPT_EXPORT$REASON)}: ${event.observation.reason}`\n : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isMessageEvent(event)) {\n const parsed = parseMessageFromEvent(event).trim();\n if (event.source === \"agent\") {\n const { reasoning, message } = splitInlineThink(parsed);\n [reasoning, message].filter(Boolean).forEach((content) => {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content,\n timestamp: event.timestamp,\n });\n });\n } else if (parsed) {\n entries.push({\n kind: \"message\",\n author: \"user\",\n content: parsed,\n timestamp: event.timestamp,\n });\n }\n continue;\n }\n\n if (isStreamingDeltaEvent(event)) {\n const { reasoning: inlineThink, message } = splitInlineThink(\n event.content ?? \"\",\n { streaming: true },\n );\n const reasoningContent = [\n event.reasoning_content?.trim() || \"\",\n inlineThink,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n if (reasoningContent) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content: reasoningContent,\n timestamp: event.timestamp,\n });\n }\n if (message.trim()) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content: message.trim(),\n timestamp: event.timestamp,\n });\n }\n continue;\n }\n\n if (isAgentErrorEvent(event)) {\n entries.push({\n kind: \"error\",\n content: event.error,\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isActionEvent(event)) {\n if (event.action.kind === \"FinishAction\") {\n const content = event.action.message.trim();\n if (content) {\n entries.push({\n kind: \"message\",\n author: \"assistant\",\n content,\n timestamp: event.timestamp,\n });\n }\n } else {\n entries.push({\n kind: \"tool\",\n summary: getActionSummary(event),\n details: includeToolDetails ? getSafeActionDetails(event) : \"\",\n timestamp: event.timestamp,\n });\n }\n continue;\n }\n\n if (isObservationEvent(event)) {\n const correspondingAction = actionsById.get(event.action_id);\n entries.push({\n kind: \"tool\",\n summary: getObservationSummary(event, correspondingAction),\n details: includeToolDetails\n ? getSafeObservationDetails(event, correspondingAction)\n : \"\",\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isACPToolCallEvent(event)) {\n entries.push({\n kind: \"tool\",\n summary:\n stripRedundantTitlePrefix(event) ||\n i18n.t(I18nKey.ACTION_MESSAGE$ACP_TOOL),\n details: includeToolDetails ? getACPToolCallContent(event) : \"\",\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (isHookExecutionEvent(event)) {\n entries.push({\n kind: \"tool\",\n summary: i18n.t(I18nKey.TRANSCRIPT_EXPORT$HOOK, {\n command: truncate(cleanInlineText(event.hook_command), 100),\n }),\n details: includeToolDetails ? getHookDetails(event) : \"\",\n timestamp: event.timestamp,\n });\n continue;\n }\n\n if (\n isConversationStateUpdateEvent(event) &&\n isGoalConversationStateUpdateEvent(event)\n ) {\n entries.push({\n kind: \"note\",\n summary: `${i18n.t(I18nKey.GOAL$PREFIX)} ${i18n.t(\n {\n running: I18nKey.GOAL$STATUS_RUNNING,\n complete: I18nKey.GOAL$STATUS_COMPLETE,\n capped: I18nKey.GOAL$STATUS_CAPPED,\n interrupted: I18nKey.GOAL$STATUS_INTERRUPTED,\n }[event.value.status],\n )}`,\n content: [event.value.objective, event.value.verdict?.missing || \"\"]\n .filter(Boolean)\n .join(\"\\n\\n\"),\n timestamp: event.timestamp,\n });\n }\n } catch {\n // Runtime event payloads may be older than the local TypeScript schema.\n // Skip malformed entries instead of aborting an otherwise valid export.\n }\n }\n\n return entries;\n};\n\nconst markdownTimestamp = (\n entry: TranscriptEntry,\n options: TranscriptExportOptions,\n): string =>\n options.includeTimestamps\n ? `<sub>${escapeHtml(formatTimestamp(entry.timestamp))}</sub>\\n\\n`\n : \"\";\n\nconst markdownFence = (content: string): string => {\n const longestRun = Math.max(\n 0,\n ...Array.from(content.matchAll(/`+/g), (match) => match[0].length),\n );\n const fence = \"`\".repeat(Math.max(3, longestRun + 1));\n return `${fence}text\\n${content}\\n${fence}`;\n};\n\nexport const eventsToMarkdown = (\n events: OpenHandsEvent[],\n options: TranscriptExportOptions,\n): string => {\n const lines = [`# ${sanitizeMarkdownText(safeTitle(options.title))}`, \"\"];\n\n if (options.model) {\n lines.push(\n `**${i18n.t(I18nKey.TRANSCRIPT_EXPORT$MODEL)}:** ${sanitizeMarkdownText(cleanInlineText(options.model))}`,\n \"\",\n );\n }\n\n for (const entry of buildTranscriptEntries(\n events,\n options.includeToolDetails,\n )) {\n const timestamp = markdownTimestamp(entry, options);\n if (entry.kind === \"message\") {\n const author =\n entry.author === \"user\"\n ? i18n.t(I18nKey.TRANSCRIPT_EXPORT$USER)\n : i18n.t(I18nKey.CHAT_INTERFACE$ASSISTANT);\n lines.push(\n `## ${author}`,\n \"\",\n timestamp + sanitizeMarkdownText(entry.content),\n \"\",\n );\n } else if (entry.kind === \"error\") {\n const quoted = entry.content\n .split(\"\\n\")\n .map((line) => `> ${sanitizeMarkdownText(line)}`)\n .join(\"\\n\");\n lines.push(\n `## ${i18n.t(I18nKey.COMMON$ERROR)}`,\n \"\",\n timestamp + quoted,\n \"\",\n );\n } else if (entry.kind === \"note\") {\n lines.push(\n `> **${escapeHtml(entry.summary)}**`,\n \"\",\n timestamp + sanitizeMarkdownText(entry.content),\n \"\",\n );\n } else if (options.includeToolDetails && entry.details) {\n lines.push(\n \"<details>\",\n `<summary><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}</summary>`,\n \"\",\n timestamp + markdownFence(entry.details),\n \"\",\n \"</details>\",\n \"\",\n );\n } else {\n const timestampMarkup = timestamp ? `<br>${timestamp.trimEnd()}` : \"\";\n lines.push(\n `<p><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}${timestampMarkup}</p>`,\n \"\",\n );\n }\n }\n\n return `${lines.join(\"\\n\").trim()}\\n`;\n};\n\nconst htmlTimestamp = (\n entry: TranscriptEntry,\n options: TranscriptExportOptions,\n): string => {\n if (!options.includeTimestamps) return \"\";\n const timestamp = formatTimestamp(entry.timestamp);\n return `<time datetime=\"${escapeHtml(timestamp)}\">${escapeHtml(timestamp)}</time>`;\n};\n\nexport const eventsToHtml = (\n events: OpenHandsEvent[],\n options: TranscriptExportOptions,\n): string => {\n const title = safeTitle(options.title);\n const body = buildTranscriptEntries(events, options.includeToolDetails)\n .map((entry) => {\n const timestamp = htmlTimestamp(entry, options);\n if (entry.kind === \"message\") {\n const author =\n entry.author === \"user\"\n ? i18n.t(I18nKey.TRANSCRIPT_EXPORT$USER)\n : i18n.t(I18nKey.CHAT_INTERFACE$ASSISTANT);\n return `<section class=\"message ${entry.author.toLowerCase()}\">\n <header><h2>${escapeHtml(author)}</h2>${timestamp}</header>\n <div class=\"content\">${escapeHtml(entry.content)}</div>\n</section>`;\n }\n if (entry.kind === \"error\") {\n return `<section class=\"message error\">\n <header><h2>${escapeHtml(i18n.t(I18nKey.COMMON$ERROR))}</h2>${timestamp}</header>\n <div class=\"content\">${escapeHtml(entry.content)}</div>\n</section>`;\n }\n if (entry.kind === \"note\") {\n return `<aside class=\"note\">\n <header><strong>${escapeHtml(entry.summary)}</strong>${timestamp}</header>\n ${entry.content ? `<div class=\"content\">${escapeHtml(entry.content)}</div>` : \"\"}\n</aside>`;\n }\n const details =\n options.includeToolDetails && entry.details\n ? `<details>\n <summary><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}${timestamp}</summary>\n <pre>${escapeHtml(entry.details)}</pre>\n</details>`\n : `<div class=\"tool-summary\"><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$TOOL))}:</strong> ${escapeHtml(entry.summary)}${timestamp}</div>`;\n return details;\n })\n .join(\"\\n\");\n\n const model = options.model\n ? `<p class=\"model\"><strong>${escapeHtml(i18n.t(I18nKey.TRANSCRIPT_EXPORT$MODEL))}:</strong> ${escapeHtml(cleanInlineText(options.model))}</p>`\n : \"\";\n\n return `<!doctype html>\n<html lang=\"${escapeHtml(i18n.resolvedLanguage || i18n.language || \"en\")}\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src 'unsafe-inline'; img-src data:\">\n <title>${escapeHtml(title)}</title>\n <style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, sans-serif; }\n body { margin: 0; background: #111827; color: #e5e7eb; line-height: 1.55; }\n main { box-sizing: border-box; width: min(860px, 100%); margin: 0 auto; padding: 48px 24px 80px; }\n h1 { margin: 0; font-size: 2rem; }\n h2 { margin: 0; font-size: 1rem; }\n .model { margin: 8px 0 32px; color: #9ca3af; }\n .message, details, .tool-summary, .note { margin: 16px 0; border: 1px solid #374151; border-radius: 10px; padding: 16px; background: #1f2937; }\n .user { border-left: 4px solid #60a5fa; }\n .assistant { border-left: 4px solid #34d399; }\n .error { border-left: 4px solid #f87171; }\n .note { border-left: 4px solid #a78bfa; }\n header, summary, .tool-summary { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }\n summary { cursor: pointer; }\n time { flex: none; color: #9ca3af; font-size: .75rem; font-weight: 400; }\n .content { margin-top: 10px; white-space: pre-wrap; overflow-wrap: anywhere; }\n pre { margin: 14px 0 0; padding: 14px; overflow-x: auto; border-radius: 7px; background: #111827; color: #d1d5db; white-space: pre-wrap; overflow-wrap: anywhere; }\n @media (prefers-color-scheme: light) {\n body { background: #f9fafb; color: #111827; }\n .message, details, .tool-summary, .note { border-color: #d1d5db; background: #fff; }\n pre { background: #f3f4f6; color: #1f2937; }\n .model, time { color: #6b7280; }\n }\n </style>\n</head>\n<body>\n <main>\n <h1>${escapeHtml(title)}</h1>\n ${model}\n ${body}\n </main>\n</body>\n</html>\n`;\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ require(`../../_virtual/_rolldown/runtime.cjs`);var e=(e,t)=>e.timestamp.localeCompare(t.timestamp),t=async(t,n,r)=>{let i=[],a=new Set,o=new Set,s,c,l=!1,u=!1;for(;;){let e=await n({limit:100,sortOrder:`TIMESTAMP_DESC`,strictPagination:!0,...c?{pageId:c}:{},...s?{timestampLt:s}:{}});if(!Array.isArray(e.items))throw Error(`Invalid transcript history response: expected page.items to be an array.`);i.push(...e.items);let t,d=!1;if(e.items.forEach(e=>{a.has(e.id)||(a.add(e.id),d=!0),(!t||e.timestamp<t)&&(t=e.timestamp)}),e.next_page_id){if(o.has(e.next_page_id))throw Error(`Transcript history pagination repeated a page cursor.`);o.add(e.next_page_id),c=e.next_page_id,s=void 0,l=!0;continue}if(l&&!u||e.items.length<100)break;if(r===void 0)throw Error(`Transcript history pagination cannot prove that all events were loaded.`);if(!t||s&&(!d||t>=s))throw Error(`Transcript history pagination did not advance.`);c=void 0,s=t,u=!0}let d=new Map;i.slice().reverse().forEach(e=>{d.has(e.id)||d.set(e.id,e)}),t.forEach(e=>{d.has(e.id)||d.set(e.id,e)});let f=[...d.values()].sort(e);if(r!==void 0&&a.size<r)throw Error(`Transcript history is incomplete: expected ${r} persisted events, received ${a.size}.`);return f};exports.loadCompleteTranscriptEvents=t;
2
+ //# sourceMappingURL=load-complete-events.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-complete-events.cjs","names":[],"sources":["../../../src/utils/transcript-export/load-complete-events.ts"],"sourcesContent":["import type { OpenHandsEvent } from \"#/types/agent-server/core\";\n\nexport const TRANSCRIPT_HISTORY_PAGE_SIZE = 100;\n\ninterface TranscriptEventSearchOptions {\n limit: number;\n sortOrder: \"TIMESTAMP_DESC\";\n pageId?: string;\n timestampLt?: string;\n strictPagination: true;\n}\n\ninterface TranscriptEventPage {\n items: OpenHandsEvent[];\n next_page_id?: string | null;\n}\n\ntype SearchTranscriptEvents = (\n options: TranscriptEventSearchOptions,\n) => Promise<TranscriptEventPage>;\n\nconst compareEventTimestamps = (\n first: OpenHandsEvent,\n second: OpenHandsEvent,\n): number => first.timestamp.localeCompare(second.timestamp);\n\n/**\n * Loads the persisted history from the newest page back to the beginning,\n * then merges any live store events that have not persisted yet. The timestamp\n * anchor matches the chat's existing history pagination, while id-based\n * de-duplication keeps the result stable if pages overlap.\n */\nexport const loadCompleteTranscriptEvents = async (\n loadedEvents: OpenHandsEvent[],\n searchEvents: SearchTranscriptEvents,\n expectedEventCount?: number,\n): Promise<OpenHandsEvent[]> => {\n const persistedDescending: OpenHandsEvent[] = [];\n const fetchedEventIds = new Set<string>();\n const seenPageIds = new Set<string>();\n let oldestTimestamp: string | undefined;\n let pageId: string | undefined;\n let usedCursor = false;\n let usingTimestampFallback = false;\n\n while (true) {\n const page = await searchEvents({\n limit: TRANSCRIPT_HISTORY_PAGE_SIZE,\n sortOrder: \"TIMESTAMP_DESC\",\n strictPagination: true,\n ...(pageId ? { pageId } : {}),\n ...(oldestTimestamp ? { timestampLt: oldestTimestamp } : {}),\n });\n\n if (!Array.isArray(page.items)) {\n throw new Error(\n \"Invalid transcript history response: expected page.items to be an array.\",\n );\n }\n\n persistedDescending.push(...page.items);\n let pageOldestTimestamp: string | undefined;\n let addedEvent = false;\n page.items.forEach((event) => {\n if (!fetchedEventIds.has(event.id)) {\n fetchedEventIds.add(event.id);\n addedEvent = true;\n }\n if (!pageOldestTimestamp || event.timestamp < pageOldestTimestamp) {\n pageOldestTimestamp = event.timestamp;\n }\n });\n\n if (page.next_page_id) {\n if (seenPageIds.has(page.next_page_id)) {\n throw new Error(\n \"Transcript history pagination repeated a page cursor.\",\n );\n }\n seenPageIds.add(page.next_page_id);\n pageId = page.next_page_id;\n oldestTimestamp = undefined;\n usedCursor = true;\n continue;\n }\n\n // Once a server supplies a cursor, a page without a next cursor is an\n // explicit exhaustion signal, even when the final page is exactly full.\n if (usedCursor && !usingTimestampFallback) break;\n if (page.items.length < TRANSCRIPT_HISTORY_PAGE_SIZE) break;\n\n // Some older servers omit cursors for filtered searches. A timestamp\n // fallback is safe to attempt only when an independent event count can\n // prove completeness; otherwise fail instead of exporting a partial tail.\n if (expectedEventCount === undefined) {\n throw new Error(\n \"Transcript history pagination cannot prove that all events were loaded.\",\n );\n }\n if (!pageOldestTimestamp) {\n throw new Error(\"Transcript history pagination did not advance.\");\n }\n if (\n oldestTimestamp &&\n (!addedEvent || pageOldestTimestamp >= oldestTimestamp)\n ) {\n throw new Error(\"Transcript history pagination did not advance.\");\n }\n\n pageId = undefined;\n oldestTimestamp = pageOldestTimestamp;\n usingTimestampFallback = true;\n }\n\n const eventsById = new Map<string, OpenHandsEvent>();\n persistedDescending\n .slice()\n .reverse()\n .forEach((event) => {\n if (!eventsById.has(event.id)) eventsById.set(event.id, event);\n });\n loadedEvents.forEach((event) => {\n if (!eventsById.has(event.id)) eventsById.set(event.id, event);\n });\n // Array.prototype.sort is stable, so equal-timestamp events keep the causal\n // order returned by the server/store rather than being reordered by id.\n const completeEvents = [...eventsById.values()].sort(compareEventTimestamps);\n if (\n expectedEventCount !== undefined &&\n fetchedEventIds.size < expectedEventCount\n ) {\n throw new Error(\n `Transcript history is incomplete: expected ${expectedEventCount} persisted events, received ${fetchedEventIds.size}.`,\n );\n }\n return completeEvents;\n};\n"],"mappings":"gDAqBA,IAAM,GACJ,EACA,IACW,EAAM,UAAU,cAAc,EAAO,UAAU,CAQ/C,EAA+B,MAC1C,EACA,EACA,IAC8B,CAC9B,IAAM,EAAwC,EAAE,CAC1C,EAAkB,IAAI,IACtB,EAAc,IAAI,IACpB,EACA,EACA,EAAa,GACb,EAAyB,GAE7B,OAAa,CACX,IAAM,EAAO,MAAM,EAAa,CAC9B,MAAA,IACA,UAAW,iBACX,iBAAkB,GAClB,GAAI,EAAS,CAAE,SAAQ,CAAG,EAAE,CAC5B,GAAI,EAAkB,CAAE,YAAa,EAAiB,CAAG,EAAE,CAC5D,CAAC,CAEF,GAAI,CAAC,MAAM,QAAQ,EAAK,MAAM,CAC5B,MAAU,MACR,2EACD,CAGH,EAAoB,KAAK,GAAG,EAAK,MAAM,CACvC,IAAI,EACA,EAAa,GAWjB,GAVA,EAAK,MAAM,QAAS,GAAU,CACvB,EAAgB,IAAI,EAAM,GAAG,GAChC,EAAgB,IAAI,EAAM,GAAG,CAC7B,EAAa,KAEX,CAAC,GAAuB,EAAM,UAAY,KAC5C,EAAsB,EAAM,YAE9B,CAEE,EAAK,aAAc,CACrB,GAAI,EAAY,IAAI,EAAK,aAAa,CACpC,MAAU,MACR,wDACD,CAEH,EAAY,IAAI,EAAK,aAAa,CAClC,EAAS,EAAK,aACd,EAAkB,IAAA,GAClB,EAAa,GACb,SAMF,GADI,GAAc,CAAC,GACf,EAAK,MAAM,OAAA,IAAuC,MAKtD,GAAI,IAAuB,IAAA,GACzB,MAAU,MACR,0EACD,CAKH,GAHI,CAAC,GAIH,IACC,CAAC,GAAc,GAAuB,GAEvC,MAAU,MAAM,iDAAiD,CAGnE,EAAS,IAAA,GACT,EAAkB,EAClB,EAAyB,GAG3B,IAAM,EAAa,IAAI,IACvB,EACG,OAAO,CACP,SAAS,CACT,QAAS,GAAU,CACb,EAAW,IAAI,EAAM,GAAG,EAAE,EAAW,IAAI,EAAM,GAAI,EAAM,EAC9D,CACJ,EAAa,QAAS,GAAU,CACzB,EAAW,IAAI,EAAM,GAAG,EAAE,EAAW,IAAI,EAAM,GAAI,EAAM,EAC9D,CAGF,IAAM,EAAiB,CAAC,GAAG,EAAW,QAAQ,CAAC,CAAC,KAAK,EAAuB,CAC5E,GACE,IAAuB,IAAA,IACvB,EAAgB,KAAO,EAEvB,MAAU,MACR,8CAA8C,EAAmB,8BAA8B,EAAgB,KAAK,GACrH,CAEH,OAAO"}
@@ -0,0 +1,22 @@
1
+ import type { OpenHandsEvent } from "#/types/agent-server/core";
2
+ export declare const TRANSCRIPT_HISTORY_PAGE_SIZE = 100;
3
+ interface TranscriptEventSearchOptions {
4
+ limit: number;
5
+ sortOrder: "TIMESTAMP_DESC";
6
+ pageId?: string;
7
+ timestampLt?: string;
8
+ strictPagination: true;
9
+ }
10
+ interface TranscriptEventPage {
11
+ items: OpenHandsEvent[];
12
+ next_page_id?: string | null;
13
+ }
14
+ type SearchTranscriptEvents = (options: TranscriptEventSearchOptions) => Promise<TranscriptEventPage>;
15
+ /**
16
+ * Loads the persisted history from the newest page back to the beginning,
17
+ * then merges any live store events that have not persisted yet. The timestamp
18
+ * anchor matches the chat's existing history pagination, while id-based
19
+ * de-duplication keeps the result stable if pages overlap.
20
+ */
21
+ export declare const loadCompleteTranscriptEvents: (loadedEvents: OpenHandsEvent[], searchEvents: SearchTranscriptEvents, expectedEventCount?: number) => Promise<OpenHandsEvent[]>;
22
+ export {};
@@ -0,0 +1,39 @@
1
+ var e = (e, t) => e.timestamp.localeCompare(t.timestamp), t = async (t, n, r) => {
2
+ let i = [], a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set(), s, c, l = !1, u = !1;
3
+ for (;;) {
4
+ let e = await n({
5
+ limit: 100,
6
+ sortOrder: "TIMESTAMP_DESC",
7
+ strictPagination: !0,
8
+ ...c ? { pageId: c } : {},
9
+ ...s ? { timestampLt: s } : {}
10
+ });
11
+ if (!Array.isArray(e.items)) throw Error("Invalid transcript history response: expected page.items to be an array.");
12
+ i.push(...e.items);
13
+ let t, d = !1;
14
+ if (e.items.forEach((e) => {
15
+ a.has(e.id) || (a.add(e.id), d = !0), (!t || e.timestamp < t) && (t = e.timestamp);
16
+ }), e.next_page_id) {
17
+ if (o.has(e.next_page_id)) throw Error("Transcript history pagination repeated a page cursor.");
18
+ o.add(e.next_page_id), c = e.next_page_id, s = void 0, l = !0;
19
+ continue;
20
+ }
21
+ if (l && !u || e.items.length < 100) break;
22
+ if (r === void 0) throw Error("Transcript history pagination cannot prove that all events were loaded.");
23
+ if (!t || s && (!d || t >= s)) throw Error("Transcript history pagination did not advance.");
24
+ c = void 0, s = t, u = !0;
25
+ }
26
+ let d = /* @__PURE__ */ new Map();
27
+ i.slice().reverse().forEach((e) => {
28
+ d.has(e.id) || d.set(e.id, e);
29
+ }), t.forEach((e) => {
30
+ d.has(e.id) || d.set(e.id, e);
31
+ });
32
+ let f = [...d.values()].sort(e);
33
+ if (r !== void 0 && a.size < r) throw Error(`Transcript history is incomplete: expected ${r} persisted events, received ${a.size}.`);
34
+ return f;
35
+ };
36
+ //#endregion
37
+ export { t as loadCompleteTranscriptEvents };
38
+
39
+ //# sourceMappingURL=load-complete-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-complete-events.js","names":[],"sources":["../../../src/utils/transcript-export/load-complete-events.ts"],"sourcesContent":["import type { OpenHandsEvent } from \"#/types/agent-server/core\";\n\nexport const TRANSCRIPT_HISTORY_PAGE_SIZE = 100;\n\ninterface TranscriptEventSearchOptions {\n limit: number;\n sortOrder: \"TIMESTAMP_DESC\";\n pageId?: string;\n timestampLt?: string;\n strictPagination: true;\n}\n\ninterface TranscriptEventPage {\n items: OpenHandsEvent[];\n next_page_id?: string | null;\n}\n\ntype SearchTranscriptEvents = (\n options: TranscriptEventSearchOptions,\n) => Promise<TranscriptEventPage>;\n\nconst compareEventTimestamps = (\n first: OpenHandsEvent,\n second: OpenHandsEvent,\n): number => first.timestamp.localeCompare(second.timestamp);\n\n/**\n * Loads the persisted history from the newest page back to the beginning,\n * then merges any live store events that have not persisted yet. The timestamp\n * anchor matches the chat's existing history pagination, while id-based\n * de-duplication keeps the result stable if pages overlap.\n */\nexport const loadCompleteTranscriptEvents = async (\n loadedEvents: OpenHandsEvent[],\n searchEvents: SearchTranscriptEvents,\n expectedEventCount?: number,\n): Promise<OpenHandsEvent[]> => {\n const persistedDescending: OpenHandsEvent[] = [];\n const fetchedEventIds = new Set<string>();\n const seenPageIds = new Set<string>();\n let oldestTimestamp: string | undefined;\n let pageId: string | undefined;\n let usedCursor = false;\n let usingTimestampFallback = false;\n\n while (true) {\n const page = await searchEvents({\n limit: TRANSCRIPT_HISTORY_PAGE_SIZE,\n sortOrder: \"TIMESTAMP_DESC\",\n strictPagination: true,\n ...(pageId ? { pageId } : {}),\n ...(oldestTimestamp ? { timestampLt: oldestTimestamp } : {}),\n });\n\n if (!Array.isArray(page.items)) {\n throw new Error(\n \"Invalid transcript history response: expected page.items to be an array.\",\n );\n }\n\n persistedDescending.push(...page.items);\n let pageOldestTimestamp: string | undefined;\n let addedEvent = false;\n page.items.forEach((event) => {\n if (!fetchedEventIds.has(event.id)) {\n fetchedEventIds.add(event.id);\n addedEvent = true;\n }\n if (!pageOldestTimestamp || event.timestamp < pageOldestTimestamp) {\n pageOldestTimestamp = event.timestamp;\n }\n });\n\n if (page.next_page_id) {\n if (seenPageIds.has(page.next_page_id)) {\n throw new Error(\n \"Transcript history pagination repeated a page cursor.\",\n );\n }\n seenPageIds.add(page.next_page_id);\n pageId = page.next_page_id;\n oldestTimestamp = undefined;\n usedCursor = true;\n continue;\n }\n\n // Once a server supplies a cursor, a page without a next cursor is an\n // explicit exhaustion signal, even when the final page is exactly full.\n if (usedCursor && !usingTimestampFallback) break;\n if (page.items.length < TRANSCRIPT_HISTORY_PAGE_SIZE) break;\n\n // Some older servers omit cursors for filtered searches. A timestamp\n // fallback is safe to attempt only when an independent event count can\n // prove completeness; otherwise fail instead of exporting a partial tail.\n if (expectedEventCount === undefined) {\n throw new Error(\n \"Transcript history pagination cannot prove that all events were loaded.\",\n );\n }\n if (!pageOldestTimestamp) {\n throw new Error(\"Transcript history pagination did not advance.\");\n }\n if (\n oldestTimestamp &&\n (!addedEvent || pageOldestTimestamp >= oldestTimestamp)\n ) {\n throw new Error(\"Transcript history pagination did not advance.\");\n }\n\n pageId = undefined;\n oldestTimestamp = pageOldestTimestamp;\n usingTimestampFallback = true;\n }\n\n const eventsById = new Map<string, OpenHandsEvent>();\n persistedDescending\n .slice()\n .reverse()\n .forEach((event) => {\n if (!eventsById.has(event.id)) eventsById.set(event.id, event);\n });\n loadedEvents.forEach((event) => {\n if (!eventsById.has(event.id)) eventsById.set(event.id, event);\n });\n // Array.prototype.sort is stable, so equal-timestamp events keep the causal\n // order returned by the server/store rather than being reordered by id.\n const completeEvents = [...eventsById.values()].sort(compareEventTimestamps);\n if (\n expectedEventCount !== undefined &&\n fetchedEventIds.size < expectedEventCount\n ) {\n throw new Error(\n `Transcript history is incomplete: expected ${expectedEventCount} persisted events, received ${fetchedEventIds.size}.`,\n );\n }\n return completeEvents;\n};\n"],"mappings":"AAqBA,IAAM,KACJ,GACA,MACW,EAAM,UAAU,cAAc,EAAO,UAAU,EAQ/C,IAA+B,OAC1C,GACA,GACA,MAC8B;CAC9B,IAAM,IAAwC,EAAE,EAC1C,oBAAkB,IAAI,KAAa,EACnC,oBAAc,IAAI,KAAa,EACjC,GACA,GACA,IAAa,IACb,IAAyB;AAE7B,UAAa;EACX,IAAM,IAAO,MAAM,EAAa;GAC9B,OAAA;GACA,WAAW;GACX,kBAAkB;GAClB,GAAI,IAAS,EAAE,WAAQ,GAAG,EAAE;GAC5B,GAAI,IAAkB,EAAE,aAAa,GAAiB,GAAG,EAAE;GAC5D,CAAC;AAEF,MAAI,CAAC,MAAM,QAAQ,EAAK,MAAM,CAC5B,OAAU,MACR,2EACD;AAGH,IAAoB,KAAK,GAAG,EAAK,MAAM;EACvC,IAAI,GACA,IAAa;AAWjB,MAVA,EAAK,MAAM,SAAS,MAAU;AAK5B,GAJK,EAAgB,IAAI,EAAM,GAAG,KAChC,EAAgB,IAAI,EAAM,GAAG,EAC7B,IAAa,MAEX,CAAC,KAAuB,EAAM,YAAY,OAC5C,IAAsB,EAAM;IAE9B,EAEE,EAAK,cAAc;AACrB,OAAI,EAAY,IAAI,EAAK,aAAa,CACpC,OAAU,MACR,wDACD;AAKH,GAHA,EAAY,IAAI,EAAK,aAAa,EAClC,IAAS,EAAK,cACd,IAAkB,KAAA,GAClB,IAAa;AACb;;AAMF,MADI,KAAc,CAAC,KACf,EAAK,MAAM,SAAA,IAAuC;AAKtD,MAAI,MAAuB,KAAA,EACzB,OAAU,MACR,0EACD;AAKH,MAHI,CAAC,KAIH,MACC,CAAC,KAAc,KAAuB,GAEvC,OAAU,MAAM,iDAAiD;AAKnE,EAFA,IAAS,KAAA,GACT,IAAkB,GAClB,IAAyB;;CAG3B,IAAM,oBAAa,IAAI,KAA6B;AAOpD,CANA,EACG,OAAO,CACP,SAAS,CACT,SAAS,MAAU;AAClB,EAAK,EAAW,IAAI,EAAM,GAAG,IAAE,EAAW,IAAI,EAAM,IAAI,EAAM;GAC9D,EACJ,EAAa,SAAS,MAAU;AAC9B,EAAK,EAAW,IAAI,EAAM,GAAG,IAAE,EAAW,IAAI,EAAM,IAAI,EAAM;GAC9D;CAGF,IAAM,IAAiB,CAAC,GAAG,EAAW,QAAQ,CAAC,CAAC,KAAK,EAAuB;AAC5E,KACE,MAAuB,KAAA,KACvB,EAAgB,OAAO,EAEvB,OAAU,MACR,8CAA8C,EAAmB,8BAA8B,EAAgB,KAAK,GACrH;AAEH,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openhands/agent-canvas",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Agent Canvas UI for OpenHands - run AI coding agents with a visual interface",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -19,7 +19,7 @@
19
19
  *
20
20
  * Usage:
21
21
  * node scripts/check-sdk-version-sync.mjs
22
- * EXPECTED_SDK_VERSION=1.33.0 node scripts/check-sdk-version-sync.mjs
22
+ * EXPECTED_SDK_VERSION=1.35.0 node scripts/check-sdk-version-sync.mjs
23
23
  * node scripts/check-sdk-version-sync.mjs --check-pypi
24
24
  *
25
25
  * Environment variables:
@@ -78,7 +78,7 @@ Triggering from other repos:
78
78
  -H "Authorization: token \$GITHUB_TOKEN" \\
79
79
  -H "Accept: application/vnd.github.v3+json" \\
80
80
  https://api.github.com/repos/OpenHands/agent-canvas/dispatches \\
81
- -d '{"event_type": "sdk-version-check", "client_payload": {"version": "1.33.0"}}'
81
+ -d '{"event_type": "sdk-version-check", "client_payload": {"version": "1.35.0"}}'
82
82
  `);
83
83
  process.exit(0);
84
84
  }
@@ -260,9 +260,9 @@ async function fetchPyPIDependencies(packageName, version) {
260
260
  * Parse PyPI requires_dist array and extract SDK package versions
261
261
  *
262
262
  * PyPI returns dependencies in PEP 508 format like:
263
- * "openhands-sdk>=1.33.0,<2.0.0"
264
- * "openhands-tools==1.33.0"
265
- * "openhands-workspace (>=1.33.0)"
263
+ * "openhands-sdk>=1.35.0,<2.0.0"
264
+ * "openhands-tools==1.35.0"
265
+ * "openhands-workspace (>=1.35.0)"
266
266
  */
267
267
  function parseSdkVersionsFromRequiresDist(requiresDist) {
268
268
  const versions = {};
@@ -276,7 +276,7 @@ function parseSdkVersionsFromRequiresDist(requiresDist) {
276
276
  }
277
277
 
278
278
  // Extract the version number - look for patterns like:
279
- // ">=1.33.0", "==1.33.0", "(>=1.33.0)", "~=1.33.0"
279
+ // ">=1.35.0", "==1.35.0", "(>=1.35.0)", "~=1.35.0"
280
280
  // After the package name and before any comma or closing paren
281
281
  const versionPattern = /[><=~!]+\s*([0-9]+(?:\.[0-9]+)*)/;
282
282
  const match = dep.match(versionPattern);