@openhands/agent-canvas 1.11.0 → 1.13.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 (766) hide show
  1. package/README.md +1 -1
  2. package/README.windows.md +2 -2
  3. package/build/assets/{acp-providers-BkL3HWa3.js → acp-providers-D1PORKc0.js} +1 -1
  4. package/build/assets/active-backend-context-IqOjobNK.js +2 -0
  5. package/build/assets/{agent-context-settings-Bno1nwPL.js → agent-context-settings-DMrObcIS.js} +1 -1
  6. package/build/assets/agent-profiles-settings-DororXN5.js +1 -0
  7. package/build/assets/agent-server-conversation-service.api-DWBe0rbX.js +86 -0
  8. package/build/assets/{agent-settings-h8hQz-IU.js → agent-settings-BJVk92PU.js} +1 -1
  9. package/build/assets/agent-settings-COfJsQ1d.js +1 -0
  10. package/build/assets/{alert-banner-lrK-2_0Y.js → alert-banner-CzZsm7ms.js} +1 -1
  11. package/build/assets/{api-key-entry-screen-Qsb83VX1.js → api-key-entry-screen-D8Fade_-.js} +1 -1
  12. package/build/assets/app-settings-CpyGB3AT.js +1 -0
  13. package/build/assets/{automation-detail-7LkL91j9.js → automation-detail-B-jQ39Mm.js} +1 -1
  14. package/build/assets/{automation-export-U2QNyNy6.js → automation-export-B1dywoqk.js} +1 -1
  15. package/build/assets/{automation-setup-route-Bel9_Lue.js → automation-setup-route-C-bWUZBi.js} +1 -1
  16. package/build/assets/{automation-templates-CRLDssaI.js → automation-templates-DgpCGOJV.js} +1 -1
  17. package/build/assets/{automations-list-B2iV3ZKW.js → automations-list-DnMxlxsL.js} +1 -1
  18. package/build/assets/{back-nav-button-B3pYwmUJ.js → back-nav-button-HHEneWMw.js} +1 -1
  19. package/build/assets/backend-form-modal-DiVrD4Cm.js +1 -0
  20. package/build/assets/{backend-synced-settings-badge-DB4717Iu.js → backend-synced-settings-badge-7MIjpr8M.js} +1 -1
  21. package/build/assets/{badge-yR53enbU.js → badge-CpYmcVZV.js} +1 -1
  22. package/build/assets/{base-modal-3NmIOKDm.js → base-modal-Fnh6Uln9.js} +1 -1
  23. package/build/assets/bot-BQZx8e2i.js +1 -0
  24. package/build/assets/{brand-button-CJcwjnfb.js → brand-button-swT1RyO0.js} +1 -1
  25. package/build/assets/browser-B9AbV6kG.js +7 -0
  26. package/build/assets/{browser-tab-A94o33Vn.js → browser-tab-zAY12m_i.js} +1 -1
  27. package/build/assets/{chat-send-button-B8n6-DQA.js → chat-send-button-DsJtivmL.js} +1 -1
  28. package/build/assets/check-WAFXrrs_.js +1 -0
  29. package/build/assets/chevron-down-CifNWzme.js +1 -0
  30. package/build/assets/circle-check-CtnimJa8.js +1 -0
  31. package/build/assets/{circle-plus-check-toggle-BVzv5EkZ.js → circle-plus-check-toggle-Cuzx55bo.js} +1 -1
  32. package/build/assets/{cloud-funnel-analytics-CBQdPZl_.js → cloud-funnel-analytics-86CwNdSh.js} +1 -1
  33. package/build/assets/{combobox-caret-BlmRwiM8.js → combobox-caret-D0fRotFi.js} +1 -1
  34. package/build/assets/{command-menu-PsRXVBz2.js → command-menu-BXy03FBl.js} +1 -1
  35. package/build/assets/{condenser-settings-w7L3EFvm.js → condenser-settings-BmZa0ui_.js} +1 -1
  36. package/build/assets/{confirmation-modal-DAH0XtOp.js → confirmation-modal-BgoN6lbN.js} +1 -1
  37. package/build/assets/{context-menu-list-item-BQhmFVEK.js → context-menu-list-item-Bq02tc-P.js} +1 -1
  38. package/build/assets/conversation-BPo8SvLN.js +1 -0
  39. package/build/assets/conversation-CPCVsCUY.js +90 -0
  40. package/build/assets/conversation-panel-BPo8SvLN.js +1 -0
  41. package/build/assets/{conversation-state-store-Bs8gA263.js → conversation-state-store-C5YpjMNy.js} +1 -1
  42. package/build/assets/conversation-store-Blc5xysY.js +6 -0
  43. package/build/assets/{conversation-tab-empty-state-C9sfDOlt.js → conversation-tab-empty-state-CMqo_0Bd.js} +1 -1
  44. package/build/assets/{copy-to-clipboard-button-DatoElj8.js → copy-to-clipboard-button-Cg1pF0xn.js} +1 -1
  45. package/build/assets/{device-verify-BIjXeW9N.js → device-verify-BfQLgNyq.js} +1 -1
  46. package/build/assets/{dropdown-classes-zFW7qPSK.js → dropdown-classes-BIqQr5mx.js} +1 -1
  47. package/build/assets/{entry.client-DzbDyLkV.js → entry.client-CxFjRYqH.js} +2 -2
  48. package/build/assets/{enum-filter-dropdown-CctILg5t.js → enum-filter-dropdown-C_yV4_bo.js} +1 -1
  49. package/build/assets/{environment-switch-overlay-Cvmo6clk.js → environment-switch-overlay-Bi4qbh2g.js} +1 -1
  50. package/build/assets/{extensions-hub-DOmHPGTA.js → extensions-hub-BqUINAhp.js} +1 -1
  51. package/build/assets/{extensions-navigation-6zU5M1pa.js → extensions-navigation-lraj88Wk.js} +1 -1
  52. package/build/assets/external-link-CgtpA_a1.js +1 -0
  53. package/build/assets/{file-text-RecuaId_.js → file-text-DEK4LSVw.js} +1 -1
  54. package/build/assets/files-tab-DV0L-lFE.js +1 -0
  55. package/build/assets/{form-control-classes-DLN3Qgub.js → form-control-classes-7yFSQJq_.js} +1 -1
  56. package/build/assets/format-model-name-BN_rx1Y3.js +1 -0
  57. package/build/assets/{format-relative-time-DGPQlPx0.js → format-relative-time-DSErAuVr.js} +1 -1
  58. package/build/assets/git-provider-icon-BvlLAche.js +1 -0
  59. package/build/assets/{git-repo-dropdown-B7RvO70z.js → git-repo-dropdown-ByMzpNko.js} +1 -1
  60. package/build/assets/git-repo-dropdown-C6R7hgM8.js +1 -0
  61. package/build/assets/{highlighted-source-view-CgJfD5VT.js → highlighted-source-view-C_sfncLZ.js} +1 -1
  62. package/build/assets/{home-DEZaZqYv.js → home-BOrlwLqG.js} +1 -1
  63. package/build/assets/home-BvMNC6E-.js +1 -0
  64. package/build/assets/{home-store-D7CjMN_-.js → home-store-CxqsY9Fi.js} +1 -1
  65. package/build/assets/index-home-BvMNC6E-.js +1 -0
  66. package/build/assets/info-BRVcJAUg.js +1 -0
  67. package/build/assets/{install-server-modal-BTwK5lbi.js → install-server-modal-Bl4G1zF4.js} +1 -1
  68. package/build/assets/{kebab-menu-item-content-C4CkeiJO.js → kebab-menu-item-content-BGoGFEAg.js} +1 -1
  69. package/build/assets/{launch-DVlx4v9o.js → launch-CkqiSCqi.js} +1 -1
  70. package/build/assets/{list-todo-CheUtB7F.js → list-todo-DNWlzfaM.js} +1 -1
  71. package/build/assets/llm-not-configured-banner-DLw_tu-G.js +27 -0
  72. package/build/assets/llm-settings-B-pkVCrt.js +1 -0
  73. package/build/assets/llm-settings-DSC0-IQ7.js +1 -0
  74. package/build/assets/llm-subscription-service-BAdOl5Xx.js +1 -0
  75. package/build/assets/loader-circle-B47W9XqT.js +1 -0
  76. package/build/assets/{loading-spinner-CN3riY7k.js → loading-spinner-xhnrGP4Y.js} +1 -1
  77. package/build/assets/{manage-backends-modal-HNWKLYhq.js → manage-backends-modal-DhGk5mJt.js} +1 -1
  78. package/build/assets/manifest-653b89aa.js +1 -0
  79. package/build/assets/{manifest-subpage-layout-D-m-h8_t.js → manifest-subpage-layout-CKWvL2ig.js} +1 -1
  80. package/build/assets/{map-provider-7Bp2aih5.js → map-provider-Mx8mZuE-.js} +1 -1
  81. package/build/assets/markdown-renderer-DUmk7pFc.js +8 -0
  82. package/build/assets/{mcp-gLgPP7AS.js → mcp-DCkvl6K0.js} +2 -2
  83. package/build/assets/mcp-marketplace-utils-DEbMXlQr.js +1 -0
  84. package/build/assets/messages-DSXvyc21.js +40 -0
  85. package/build/assets/{modal-body-duRaxj_K.js → modal-body-gIe21fDv.js} +1 -1
  86. package/build/assets/{modal-classes-CLEXO6dj.js → modal-classes-D66dlgZ7.js} +1 -1
  87. package/build/assets/{modal-close-button-D0aT02hs.js → modal-close-button-B6iOGYpI.js} +1 -1
  88. package/build/assets/{mouse-pointer-click-Px-dXWcS.js → mouse-pointer-click-BYX1Pw5W.js} +1 -1
  89. package/build/assets/{npm-DRzJF5Zn.js → npm-DLckoeJc.js} +1 -1
  90. package/build/assets/{onboarding-DSr8hOpk.js → onboarding-D7WDG66N.js} +1 -1
  91. package/build/assets/{onboarding-modal-C6Euf7N4.js → onboarding-modal-C_xVrFNv.js} +1 -1
  92. package/build/assets/{organization-service.api-C4GYWwj9.js → organization-service.api-D-s9z18a.js} +1 -1
  93. package/build/assets/pencil-BGOCPRyu.js +1 -0
  94. package/build/assets/{planner-tab-CZcguxTK.js → planner-tab-AKaXIIfg.js} +1 -1
  95. package/build/assets/{plugins-management-service-BmDzOQsd.js → plugins-management-service-wtmY4QQw.js} +1 -1
  96. package/build/assets/plus-zNEL8rcX.js +1 -0
  97. package/build/assets/{profiles-service.api-CoLTwjc1.js → profiles-service.api-DCMYxHMi.js} +1 -1
  98. package/build/assets/{providers-tBzTpz1w.js → providers-BjrtjX4L.js} +1 -1
  99. package/build/assets/{proxy-DCI9S-LA.js → proxy-9Z_WZggZ.js} +1 -1
  100. package/build/assets/{puzzle-B3v361yY.js → puzzle-BWLmN8z4.js} +1 -1
  101. package/build/assets/recommended-automations-launcher-CFlzhu1o.js +1 -0
  102. package/build/assets/refresh-cw-CXtFWpwv.js +1 -0
  103. package/build/assets/root-CanxKlNV.css +1 -0
  104. package/build/assets/root-DkfG_UWR.js +2 -0
  105. package/build/assets/root-layout-D75LHYhh.js +2 -0
  106. package/build/assets/{schema-field-zhsVDllR.js → schema-field-OnM5Uob_.js} +1 -1
  107. package/build/assets/{sdk-section-page-CS4GWn0y.js → sdk-section-page-m5WQm2sy.js} +1 -1
  108. package/build/assets/search-CycosyjN.js +1 -0
  109. package/build/assets/{secrets-service-DjgGduXk.js → secrets-service-B26R61C1.js} +1 -1
  110. package/build/assets/{secrets-settings-f-qahfbi.js → secrets-settings-CbLYCKOX.js} +1 -1
  111. package/build/assets/{segmented-toggle-SmvsR3jW.js → segmented-toggle-DCspm2U5.js} +1 -1
  112. package/build/assets/{settings-DQd0xLEw.js → settings-BJQI_iBM.js} +1 -1
  113. package/build/assets/{settings-dropdown-input-TWIeiG02.js → settings-dropdown-input-BI8V_Nov.js} +1 -1
  114. package/build/assets/{settings-index-BVwy9JEp.js → settings-index-BiTqJoH7.js} +1 -1
  115. package/build/assets/{settings-input-D61Vzp9e.js → settings-input-Cz62hWVW.js} +1 -1
  116. package/build/assets/{settings-list-classes-sE0ASr1s.js → settings-list-classes-z_3FW5H3.js} +1 -1
  117. package/build/assets/{settings-modal-D6D5ngET.js → settings-modal-BIrIVn97.js} +1 -1
  118. package/build/assets/{settings-service.api-DZp7E7A9.js → settings-service.api--rJmnuLa.js} +1 -1
  119. package/build/assets/{settings-switch-Drt-rF5s.js → settings-switch-BRsSI8Vs.js} +1 -1
  120. package/build/assets/{settings-utils-gw2ppAvw.js → settings-utils-Ba7vel6T.js} +1 -1
  121. package/build/assets/shared-conversation-CQK_PqHx.js +1 -0
  122. package/build/assets/shield-check-T3JsDJiM.js +1 -0
  123. package/build/assets/{sidebar-layout-Dxg6zc2K.js → sidebar-layout-Bhi3hVcu.js} +1 -1
  124. package/build/assets/{sidebar-mobile-menu-toggle-OoZBHxaT.js → sidebar-mobile-menu-toggle-YWJNRN4p.js} +1 -1
  125. package/build/assets/{sidebar-nav-link-CxLoG-dG.js → sidebar-nav-link-BSUlY5Ml.js} +1 -1
  126. package/build/assets/{sidebar-store-BJeYY-E9.js → sidebar-store-Cl1cUv_F.js} +1 -1
  127. package/build/assets/{skill-card-pill-row-B_BYBONu.js → skill-card-pill-row-BXz8L8Rn.js} +1 -1
  128. package/build/assets/{skill-icon-badge-CN41Hy9l.js → skill-icon-badge-QgfKv31M.js} +1 -1
  129. package/build/assets/{skill-scope-B1Per5XI.js → skill-scope-Dc3JPW-8.js} +1 -1
  130. package/build/assets/{skills-plugins-B3AO6sMz.js → skills-plugins-CpTV27n3.js} +1 -1
  131. package/build/assets/{skills-settings-DmmgJ6CT.js → skills-settings-CSW__IW4.js} +1 -1
  132. package/build/assets/{sparkles-g7y3r-Ut.js → sparkles-TJ0mdECe.js} +1 -1
  133. package/build/assets/{styled-tooltip-C5C07RQC.js → styled-tooltip-BUMSbgrF.js} +1 -1
  134. package/build/assets/{task-list-tab-C19Q_JNf.js → task-list-tab-mAHMOkUz.js} +1 -1
  135. package/build/assets/{terminal-CbuMRYal.js → terminal-BzxBaHx2.js} +1 -1
  136. package/build/assets/{toggle-switch-CIioisto.js → toggle-switch-O5v1FgxW.js} +1 -1
  137. package/build/assets/trash-2-C0xNVp9c.js +1 -0
  138. package/build/assets/{typography-D9tiHct7.js → typography-NOKSk9_R.js} +1 -1
  139. package/build/assets/usage-tab-tEmVN0KD.js +1 -0
  140. package/build/assets/{use-acp-credential-form-DJmmJKMo.js → use-acp-credential-form-BPNi0Zbm.js} +1 -1
  141. package/build/assets/{use-activate-agent-profile-CeFfYwu_.js → use-activate-agent-profile-D9YRQPTF.js} +1 -1
  142. package/build/assets/{use-agent-profiles-BHLkLbRR.js → use-agent-profiles-Cb2zUW3l.js} +1 -1
  143. package/build/assets/{use-can-manage-org-profiles-Bu4y8gSx.js → use-can-manage-org-profiles-Dxzq2AEd.js} +1 -1
  144. package/build/assets/{use-cloud-current-user-id-QD9x3ySO.js → use-cloud-current-user-id-Co2eJk2A.js} +1 -1
  145. package/build/assets/{use-config-CPwqciXN.js → use-config-DKAMiI5R.js} +1 -1
  146. package/build/assets/use-create-conversation-CoHTiCbI.js +1 -0
  147. package/build/assets/{use-create-secret-BsOfOLvg.js → use-create-secret-2zBlCDsF.js} +1 -1
  148. package/build/assets/use-is-authed-C52-ivnB.js +1 -0
  149. package/build/assets/{use-is-creating-conversation-CVefC9Ns.js → use-is-creating-conversation-DdaAE6jV.js} +1 -1
  150. package/build/assets/{use-launch-skill-in-chat-BcKNjxxd.js → use-launch-skill-in-chat-COnDpxCQ.js} +1 -1
  151. package/build/assets/use-llm-profiles-C_BHue65.js +1 -0
  152. package/build/assets/{use-manifest-capabilities-DBYPjyV6.js → use-manifest-capabilities-DPrQsaPP.js} +1 -1
  153. package/build/assets/{use-onboarding-completion-CtNJxkXG.js → use-onboarding-completion-CCE8OQgV.js} +1 -1
  154. package/build/assets/{use-plugins-marketplace-ZEA-gyM9.js → use-plugins-marketplace-CEiak69h.js} +1 -1
  155. package/build/assets/use-save-agent-profile-DK9idD6a.js +1 -0
  156. package/build/assets/{use-save-settings-pSjRhD_m.js → use-save-settings-DNmnbG6f.js} +1 -1
  157. package/build/assets/{use-settings-nav-items-CQgkxUbV.js → use-settings-nav-items-BlFL7YhM.js} +1 -1
  158. package/build/assets/{use-settings-BHWsOcIG.js → use-settings-wCwPaSIv.js} +1 -1
  159. package/build/assets/{use-tracking-CGCsBWhg.js → use-tracking-CVwPmhlX.js} +1 -1
  160. package/build/assets/{use-user-conversation-DRfEU8x0.js → use-user-conversation-DVtfg0B_.js} +1 -1
  161. package/build/assets/{useInfiniteQuery-DbCv0Jzd.js → useInfiniteQuery-p1xq35r2.js} +1 -1
  162. package/build/assets/{useMutation-ChpkYxI5.js → useMutation-BFDQmgk9.js} +1 -1
  163. package/build/assets/{useQueries-Cjv3E8_1.js → useQueries-DF1NAAeC.js} +1 -1
  164. package/build/assets/{useQuery-BCnzy4LX.js → useQuery-DRv--6bK.js} +1 -1
  165. package/build/assets/utils-zxEjKE70.js +1 -0
  166. package/build/assets/{vendor~browser-DJ1pl_wn.js → vendor~browser-B-fae1JU.js} +14 -14
  167. package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~kv3pap4j-oGvLV0dO.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~kv3pap4j-B8i84bh4.js} +3 -3
  168. package/build/assets/{vendor~files-tab-C87pjSpi.js → vendor~files-tab-D9wR9yM2.js} +1 -1
  169. package/build/assets/vendor~index-home~home~conversation-panel~conversation-Ipoe6hvY.js +13 -0
  170. package/build/assets/vendor~root-layout-C-IgVx6e.js +1 -0
  171. package/build/assets/{vendor~root-layout~conversation-panel~conversation-DEzjR4K7.js → vendor~root-layout~conversation-panel~conversation-Dhd_I4H4.js} +1 -1
  172. package/build/assets/{vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-U-xdsAEx.js → vendor~root-layout~conversation-panel~conversation~skills-settings~automations-list~shared-~bovqqk8e-Cc0f9kPP.js} +1 -1
  173. package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-CQR5Sa0H.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation-d7svw-BB.js} +1 -1
  174. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~gxu4j2ea-Cwhh3zLe.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~gxu4j2ea-D5DWZVc7.js} +1 -1
  175. package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~hjcjabwg-CuQhkiS7.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~hjcjabwg-4WsUP-tz.js} +2 -2
  176. package/build/assets/{verification-settings-BItwt998.js → verification-settings-B8UMQ7MG.js} +1 -1
  177. package/build/assets/{wrench-B1_H-tL1.js → wrench-DIka3hCq.js} +1 -1
  178. package/build/assets/x-BWKA2Ver.js +1 -0
  179. package/build/assets/zap-DHddTPc0.js +1 -0
  180. package/build/index.html +4 -4
  181. package/build/locales/ar/openhands.json +28 -1
  182. package/build/locales/ca/openhands.json +28 -1
  183. package/build/locales/de/openhands.json +28 -1
  184. package/build/locales/en/openhands.json +28 -1
  185. package/build/locales/es/openhands.json +28 -1
  186. package/build/locales/fr/openhands.json +28 -1
  187. package/build/locales/it/openhands.json +28 -1
  188. package/build/locales/ja/openhands.json +28 -1
  189. package/build/locales/ko-KR/openhands.json +28 -1
  190. package/build/locales/no/openhands.json +28 -1
  191. package/build/locales/pt/openhands.json +28 -1
  192. package/build/locales/tr/openhands.json +28 -1
  193. package/build/locales/uk/openhands.json +28 -1
  194. package/build/locales/zh-CN/openhands.json +28 -1
  195. package/build/locales/zh-TW/openhands.json +28 -1
  196. package/config/defaults.json +3 -3
  197. package/dist/api/agent-server-compatibility.cjs +1 -1
  198. package/dist/api/agent-server-compatibility.cjs.map +1 -1
  199. package/dist/api/agent-server-compatibility.js +1 -1
  200. package/dist/api/agent-server-compatibility.js.map +1 -1
  201. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
  202. package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
  203. package/dist/api/conversation-service/agent-server-conversation-service.api.d.ts +24 -1
  204. package/dist/api/conversation-service/agent-server-conversation-service.api.js +116 -97
  205. package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
  206. package/dist/api/llm-balance-service.cjs +2 -0
  207. package/dist/api/llm-balance-service.cjs.map +1 -0
  208. package/dist/api/llm-balance-service.d.ts +33 -0
  209. package/dist/api/llm-balance-service.js +53 -0
  210. package/dist/api/llm-balance-service.js.map +1 -0
  211. package/dist/api/llm-subscription-service.cjs +1 -1
  212. package/dist/api/llm-subscription-service.cjs.map +1 -1
  213. package/dist/api/llm-subscription-service.js +42 -34
  214. package/dist/api/llm-subscription-service.js.map +1 -1
  215. package/dist/components/conversation/index.cjs +1 -1
  216. package/dist/components/conversation/index.d.ts +0 -1
  217. package/dist/components/conversation/index.js +0 -1
  218. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs +1 -1
  219. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.cjs.map +1 -1
  220. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js +1 -1
  221. package/dist/components/conversation-events/chat/event-content-helpers/get-event-content.js.map +1 -1
  222. package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.cjs +1 -1
  223. package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.cjs.map +1 -1
  224. package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.js +24 -23
  225. package/dist/components/conversation-events/chat/event-message-components/generic-event-message-wrapper.js.map +1 -1
  226. package/dist/components/conversation-events/chat/group-events.cjs +1 -1
  227. package/dist/components/conversation-events/chat/group-events.cjs.map +1 -1
  228. package/dist/components/conversation-events/chat/group-events.d.ts +3 -3
  229. package/dist/components/conversation-events/chat/group-events.js +27 -26
  230. package/dist/components/conversation-events/chat/group-events.js.map +1 -1
  231. package/dist/components/features/automations/recommended-automations-section.d.ts +7 -0
  232. package/dist/components/features/chat/components/chat-input-actions.cjs +1 -1
  233. package/dist/components/features/chat/components/chat-input-actions.cjs.map +1 -1
  234. package/dist/components/features/chat/components/chat-input-actions.js +123 -118
  235. package/dist/components/features/chat/components/chat-input-actions.js.map +1 -1
  236. package/dist/components/features/chat/components/chat-input-grip.cjs +1 -1
  237. package/dist/components/features/chat/components/chat-input-grip.cjs.map +1 -1
  238. package/dist/components/features/chat/components/chat-input-grip.d.ts +2 -1
  239. package/dist/components/features/chat/components/chat-input-grip.js +7 -7
  240. package/dist/components/features/chat/components/chat-input-grip.js.map +1 -1
  241. package/dist/components/features/chat/components/chat-input-llm-profile-picker.cjs +1 -1
  242. package/dist/components/features/chat/components/chat-input-llm-profile-picker.cjs.map +1 -1
  243. package/dist/components/features/chat/components/chat-input-llm-profile-picker.js +61 -60
  244. package/dist/components/features/chat/components/chat-input-llm-profile-picker.js.map +1 -1
  245. package/dist/components/features/chat/components/context-window-meter.cjs +2 -0
  246. package/dist/components/features/chat/components/context-window-meter.cjs.map +1 -0
  247. package/dist/components/features/chat/components/context-window-meter.d.ts +2 -0
  248. package/dist/components/features/chat/components/context-window-meter.js +131 -0
  249. package/dist/components/features/chat/components/context-window-meter.js.map +1 -0
  250. package/dist/components/features/chat/components/context-window-ring.cjs +2 -0
  251. package/dist/components/features/chat/components/context-window-ring.cjs.map +1 -0
  252. package/dist/components/features/chat/components/context-window-ring.d.ts +26 -0
  253. package/dist/components/features/chat/components/context-window-ring.js +45 -0
  254. package/dist/components/features/chat/components/context-window-ring.js.map +1 -0
  255. package/dist/components/features/chat/custom-chat-input.cjs +1 -1
  256. package/dist/components/features/chat/custom-chat-input.cjs.map +1 -1
  257. package/dist/components/features/chat/custom-chat-input.js +68 -67
  258. package/dist/components/features/chat/custom-chat-input.js.map +1 -1
  259. package/dist/components/features/chat/model-messages.cjs +1 -1
  260. package/dist/components/features/chat/model-messages.cjs.map +1 -1
  261. package/dist/components/features/chat/model-messages.js +26 -25
  262. package/dist/components/features/chat/model-messages.js.map +1 -1
  263. package/dist/components/features/chat/path-component.cjs +1 -1
  264. package/dist/components/features/chat/path-component.cjs.map +1 -1
  265. package/dist/components/features/chat/path-component.js +9 -6
  266. package/dist/components/features/chat/path-component.js.map +1 -1
  267. package/dist/components/features/chat/plan-preview.cjs +1 -1
  268. package/dist/components/features/chat/plan-preview.js +4 -4
  269. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.cjs +1 -1
  270. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.cjs.map +1 -1
  271. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.d.ts +0 -8
  272. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.js +92 -50
  273. package/dist/components/features/chat/tool-visualizers/file-editor/file-editor.js.map +1 -1
  274. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.cjs +1 -1
  275. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.cjs.map +1 -1
  276. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.d.ts +7 -2
  277. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.js +15 -9
  278. package/dist/components/features/chat/tool-visualizers/primitives/file-path-chip.js.map +1 -1
  279. package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.cjs +2 -0
  280. package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.cjs.map +1 -0
  281. package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.d.ts +20 -0
  282. package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.js +76 -0
  283. package/dist/components/features/chat/tool-visualizers/primitives/markdown-file-preview.js.map +1 -0
  284. package/dist/components/features/controls/server-status-context-menu.cjs +1 -1
  285. package/dist/components/features/controls/server-status-context-menu.cjs.map +1 -1
  286. package/dist/components/features/controls/server-status-context-menu.d.ts +5 -3
  287. package/dist/components/features/controls/server-status-context-menu.js +8 -8
  288. package/dist/components/features/controls/server-status-context-menu.js.map +1 -1
  289. package/dist/components/features/conversation/conversation-name-context-menu.cjs +1 -1
  290. package/dist/components/features/conversation/conversation-name-context-menu.cjs.map +1 -1
  291. package/dist/components/features/conversation/conversation-name-context-menu.js +58 -61
  292. package/dist/components/features/conversation/conversation-name-context-menu.js.map +1 -1
  293. package/dist/components/features/conversation/conversation-name-with-status.cjs +1 -1
  294. package/dist/components/features/conversation/conversation-name-with-status.cjs.map +1 -1
  295. package/dist/components/features/conversation/conversation-name-with-status.js +74 -46
  296. package/dist/components/features/conversation/conversation-name-with-status.js.map +1 -1
  297. package/dist/components/features/conversation/conversation-name.cjs +1 -1
  298. package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
  299. package/dist/components/features/conversation/conversation-name.js +69 -71
  300. package/dist/components/features/conversation/conversation-name.js.map +1 -1
  301. package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.cjs +1 -1
  302. package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.cjs.map +1 -1
  303. package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.js +7 -6
  304. package/dist/components/features/conversation/conversation-tabs/conversation-tab-content/conversation-tab-content.js.map +1 -1
  305. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs +1 -1
  306. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.cjs.map +1 -1
  307. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js +92 -86
  308. package/dist/components/features/conversation/conversation-tabs/conversation-tabs-context-menu.js.map +1 -1
  309. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs +1 -1
  310. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.cjs.map +1 -1
  311. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js +81 -71
  312. package/dist/components/features/conversation/conversation-tabs/conversation-tabs.js.map +1 -1
  313. package/dist/components/features/conversation/metrics-modal/cost-section.cjs +1 -1
  314. package/dist/components/features/conversation/metrics-modal/cost-section.cjs.map +1 -1
  315. package/dist/components/features/conversation/metrics-modal/cost-section.js +6 -6
  316. package/dist/components/features/conversation/metrics-modal/cost-section.js.map +1 -1
  317. package/dist/components/features/conversation/metrics-modal/metric-row.cjs +1 -1
  318. package/dist/components/features/conversation/metrics-modal/metric-row.cjs.map +1 -1
  319. package/dist/components/features/conversation/metrics-modal/metric-row.d.ts +2 -1
  320. package/dist/components/features/conversation/metrics-modal/metric-row.js +10 -9
  321. package/dist/components/features/conversation/metrics-modal/metric-row.js.map +1 -1
  322. package/dist/components/features/conversation/metrics-modal/usage-section.cjs +1 -1
  323. package/dist/components/features/conversation/metrics-modal/usage-section.cjs.map +1 -1
  324. package/dist/components/features/conversation/metrics-modal/usage-section.js +2 -1
  325. package/dist/components/features/conversation/metrics-modal/usage-section.js.map +1 -1
  326. package/dist/components/features/conversation/usage-panel/compact-context-button.cjs +2 -0
  327. package/dist/components/features/conversation/usage-panel/compact-context-button.cjs.map +1 -0
  328. package/dist/components/features/conversation/usage-panel/compact-context-button.d.ts +16 -0
  329. package/dist/components/features/conversation/usage-panel/compact-context-button.js +59 -0
  330. package/dist/components/features/conversation/usage-panel/compact-context-button.js.map +1 -0
  331. package/dist/components/features/conversation/usage-panel/context-meter.cjs +2 -0
  332. package/dist/components/features/conversation/usage-panel/context-meter.cjs.map +1 -0
  333. package/dist/components/features/conversation/usage-panel/context-meter.d.ts +19 -0
  334. package/dist/components/features/conversation/usage-panel/context-meter.js +46 -0
  335. package/dist/components/features/conversation/usage-panel/context-meter.js.map +1 -0
  336. package/dist/components/features/conversation/usage-panel/provider-balance-card.cjs +2 -0
  337. package/dist/components/features/conversation/usage-panel/provider-balance-card.cjs.map +1 -0
  338. package/dist/components/features/conversation/usage-panel/provider-balance-card.d.ts +7 -0
  339. package/dist/components/features/conversation/usage-panel/provider-balance-card.js +57 -0
  340. package/dist/components/features/conversation/usage-panel/provider-balance-card.js.map +1 -0
  341. package/dist/components/features/conversation/usage-panel/usage-panel.cjs +2 -0
  342. package/dist/components/features/conversation/usage-panel/usage-panel.cjs.map +1 -0
  343. package/dist/components/features/conversation/usage-panel/usage-panel.d.ts +9 -0
  344. package/dist/components/features/conversation/usage-panel/usage-panel.js +68 -0
  345. package/dist/components/features/conversation/usage-panel/usage-panel.js.map +1 -0
  346. package/dist/components/features/conversation-panel/budget-display.cjs +1 -1
  347. package/dist/components/features/conversation-panel/budget-display.cjs.map +1 -1
  348. package/dist/components/features/conversation-panel/budget-display.js +10 -13
  349. package/dist/components/features/conversation-panel/budget-display.js.map +1 -1
  350. package/dist/components/features/conversation-panel/budget-progress-bar.cjs +1 -1
  351. package/dist/components/features/conversation-panel/budget-progress-bar.cjs.map +1 -1
  352. package/dist/components/features/conversation-panel/budget-progress-bar.js +2 -2
  353. package/dist/components/features/conversation-panel/budget-progress-bar.js.map +1 -1
  354. package/dist/components/features/conversation-panel/confirm-archive-modal.cjs +2 -0
  355. package/dist/components/features/conversation-panel/confirm-archive-modal.cjs.map +1 -0
  356. package/dist/components/features/conversation-panel/confirm-archive-modal.d.ts +8 -0
  357. package/dist/components/features/conversation-panel/confirm-archive-modal.js +48 -0
  358. package/dist/components/features/conversation-panel/confirm-archive-modal.js.map +1 -0
  359. package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.cjs +1 -1
  360. package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.cjs.map +1 -1
  361. package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.d.ts +3 -1
  362. package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.js +39 -34
  363. package/dist/components/features/conversation-panel/conversation-card/conversation-card-actions.js.map +1 -1
  364. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs +1 -1
  365. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs.map +1 -1
  366. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.d.ts +3 -1
  367. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js +104 -80
  368. package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js.map +1 -1
  369. package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.cjs +1 -1
  370. package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.cjs.map +1 -1
  371. package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.d.ts +7 -1
  372. package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.js +28 -20
  373. package/dist/components/features/conversation-panel/conversation-card/conversation-card-footer.js.map +1 -1
  374. package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs +1 -1
  375. package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs.map +1 -1
  376. package/dist/components/features/conversation-panel/conversation-card/conversation-card.d.ts +9 -1
  377. package/dist/components/features/conversation-panel/conversation-card/conversation-card.js +94 -84
  378. package/dist/components/features/conversation-panel/conversation-card/conversation-card.js.map +1 -1
  379. package/dist/components/features/conversation-panel/conversation-group-folder-list.cjs +1 -1
  380. package/dist/components/features/conversation-panel/conversation-group-folder-list.cjs.map +1 -1
  381. package/dist/components/features/conversation-panel/conversation-group-folder-list.d.ts +2 -1
  382. package/dist/components/features/conversation-panel/conversation-group-folder-list.js +32 -31
  383. package/dist/components/features/conversation-panel/conversation-group-folder-list.js.map +1 -1
  384. package/dist/components/features/conversation-panel/conversation-group-folder-row.cjs +1 -1
  385. package/dist/components/features/conversation-panel/conversation-group-folder-row.cjs.map +1 -1
  386. package/dist/components/features/conversation-panel/conversation-group-folder-row.d.ts +2 -1
  387. package/dist/components/features/conversation-panel/conversation-group-folder-row.js +27 -26
  388. package/dist/components/features/conversation-panel/conversation-group-folder-row.js.map +1 -1
  389. package/dist/components/features/conversation-panel/conversation-panel-filter-menu.cjs +1 -1
  390. package/dist/components/features/conversation-panel/conversation-panel-filter-menu.cjs.map +1 -1
  391. package/dist/components/features/conversation-panel/conversation-panel-filter-menu.d.ts +3 -1
  392. package/dist/components/features/conversation-panel/conversation-panel-filter-menu.js +116 -106
  393. package/dist/components/features/conversation-panel/conversation-panel-filter-menu.js.map +1 -1
  394. package/dist/components/features/conversation-panel/conversation-panel-list-helpers.cjs +1 -1
  395. package/dist/components/features/conversation-panel/conversation-panel-list-helpers.cjs.map +1 -1
  396. package/dist/components/features/conversation-panel/conversation-panel-list-helpers.d.ts +27 -0
  397. package/dist/components/features/conversation-panel/conversation-panel-list-helpers.js +69 -46
  398. package/dist/components/features/conversation-panel/conversation-panel-list-helpers.js.map +1 -1
  399. package/dist/components/features/conversation-panel/conversation-panel.cjs +1 -1
  400. package/dist/components/features/conversation-panel/conversation-panel.cjs.map +1 -1
  401. package/dist/components/features/conversation-panel/conversation-panel.js +230 -165
  402. package/dist/components/features/conversation-panel/conversation-panel.js.map +1 -1
  403. package/dist/components/features/files-tab/file-content-viewer.cjs +1 -1
  404. package/dist/components/features/files-tab/file-content-viewer.cjs.map +1 -1
  405. package/dist/components/features/files-tab/file-content-viewer.js +22 -25
  406. package/dist/components/features/files-tab/file-content-viewer.js.map +1 -1
  407. package/dist/components/features/markdown/markdown-table-scroll.cjs +1 -1
  408. package/dist/components/features/markdown/markdown-table-scroll.cjs.map +1 -1
  409. package/dist/components/features/markdown/markdown-table-scroll.js +2 -2
  410. package/dist/components/features/markdown/markdown-table-scroll.js.map +1 -1
  411. package/dist/components/features/settings/llm-profiles/profile-row.cjs +1 -1
  412. package/dist/components/features/settings/llm-profiles/profile-row.js +1 -0
  413. package/dist/components/shared/buttons/conversation-confirmation-buttons.cjs +1 -1
  414. package/dist/components/shared/buttons/conversation-confirmation-buttons.cjs.map +1 -1
  415. package/dist/components/shared/buttons/conversation-confirmation-buttons.js +2 -2
  416. package/dist/components/shared/buttons/conversation-confirmation-buttons.js.map +1 -1
  417. package/dist/components/shared/modals/confirmation-modals/base-modal.cjs +1 -1
  418. package/dist/components/shared/modals/confirmation-modals/base-modal.cjs.map +1 -1
  419. package/dist/components/shared/modals/confirmation-modals/base-modal.js +1 -1
  420. package/dist/components/shared/modals/confirmation-modals/base-modal.js.map +1 -1
  421. package/dist/components/shared/modals/settings/model-selector.cjs +1 -1
  422. package/dist/components/shared/modals/settings/model-selector.cjs.map +1 -1
  423. package/dist/components/shared/modals/settings/model-selector.js +154 -98
  424. package/dist/components/shared/modals/settings/model-selector.js.map +1 -1
  425. package/dist/config/defaults.cjs +1 -1
  426. package/dist/config/defaults.cjs.map +1 -1
  427. package/dist/config/defaults.js +3 -3
  428. package/dist/config/defaults.js.map +1 -1
  429. package/dist/constants/llm-balance.cjs +2 -0
  430. package/dist/constants/llm-balance.cjs.map +1 -0
  431. package/dist/constants/llm-balance.d.ts +13 -0
  432. package/dist/constants/llm-balance.js +6 -0
  433. package/dist/constants/llm-balance.js.map +1 -0
  434. package/dist/contexts/conversation-websocket-context.cjs +2 -2
  435. package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
  436. package/dist/contexts/conversation-websocket-context.js +217 -209
  437. package/dist/contexts/conversation-websocket-context.js.map +1 -1
  438. package/dist/hooks/chat/use-grip-resize.cjs +1 -1
  439. package/dist/hooks/chat/use-grip-resize.cjs.map +1 -1
  440. package/dist/hooks/chat/use-grip-resize.d.ts +1 -0
  441. package/dist/hooks/chat/use-grip-resize.js +39 -30
  442. package/dist/hooks/chat/use-grip-resize.js.map +1 -1
  443. package/dist/hooks/chat/use-slash-command.cjs +1 -1
  444. package/dist/hooks/chat/use-slash-command.cjs.map +1 -1
  445. package/dist/hooks/chat/use-slash-command.js +61 -60
  446. package/dist/hooks/chat/use-slash-command.js.map +1 -1
  447. package/dist/hooks/mutation/use-condense-conversation.cjs +2 -0
  448. package/dist/hooks/mutation/use-condense-conversation.cjs.map +1 -0
  449. package/dist/hooks/mutation/use-condense-conversation.d.ts +12 -0
  450. package/dist/hooks/mutation/use-condense-conversation.js +17 -0
  451. package/dist/hooks/mutation/use-condense-conversation.js.map +1 -0
  452. package/dist/hooks/mutation/use-create-conversation.cjs +1 -1
  453. package/dist/hooks/mutation/use-create-conversation.cjs.map +1 -1
  454. package/dist/hooks/mutation/use-create-conversation.js +30 -21
  455. package/dist/hooks/mutation/use-create-conversation.js.map +1 -1
  456. package/dist/hooks/mutation/use-new-conversation-command.cjs +1 -1
  457. package/dist/hooks/mutation/use-new-conversation-command.cjs.map +1 -1
  458. package/dist/hooks/mutation/use-new-conversation-command.js +1 -1
  459. package/dist/hooks/mutation/use-new-conversation-command.js.map +1 -1
  460. package/dist/hooks/query/use-conversation-metrics.cjs +1 -1
  461. package/dist/hooks/query/use-conversation-metrics.cjs.map +1 -1
  462. package/dist/hooks/query/use-conversation-metrics.js +1 -1
  463. package/dist/hooks/query/use-conversation-metrics.js.map +1 -1
  464. package/dist/hooks/query/use-llm-balance.cjs +2 -0
  465. package/dist/hooks/query/use-llm-balance.cjs.map +1 -0
  466. package/dist/hooks/query/use-llm-balance.d.ts +10 -0
  467. package/dist/hooks/query/use-llm-balance.js +24 -0
  468. package/dist/hooks/query/use-llm-balance.js.map +1 -0
  469. package/dist/hooks/query/use-search-providers.cjs +1 -1
  470. package/dist/hooks/query/use-search-providers.cjs.map +1 -1
  471. package/dist/hooks/query/use-search-providers.js +1 -1
  472. package/dist/hooks/query/use-search-providers.js.map +1 -1
  473. package/dist/hooks/use-await-context-compaction.cjs +2 -0
  474. package/dist/hooks/use-await-context-compaction.cjs.map +1 -0
  475. package/dist/hooks/use-await-context-compaction.d.ts +38 -0
  476. package/dist/hooks/use-await-context-compaction.js +61 -0
  477. package/dist/hooks/use-await-context-compaction.js.map +1 -0
  478. package/dist/hooks/use-compact-context-action.cjs +2 -0
  479. package/dist/hooks/use-compact-context-action.cjs.map +1 -0
  480. package/dist/hooks/use-compact-context-action.d.ts +10 -0
  481. package/dist/hooks/use-compact-context-action.js +61 -0
  482. package/dist/hooks/use-compact-context-action.js.map +1 -0
  483. package/dist/hooks/use-context-window-usage.cjs +2 -0
  484. package/dist/hooks/use-context-window-usage.cjs.map +1 -0
  485. package/dist/hooks/use-context-window-usage.d.ts +5 -0
  486. package/dist/hooks/use-context-window-usage.js +20 -0
  487. package/dist/hooks/use-context-window-usage.js.map +1 -0
  488. package/dist/hooks/use-conversation-name-context-menu.cjs +1 -1
  489. package/dist/hooks/use-conversation-name-context-menu.cjs.map +1 -1
  490. package/dist/hooks/use-conversation-name-context-menu.d.ts +0 -3
  491. package/dist/hooks/use-conversation-name-context-menu.js +54 -57
  492. package/dist/hooks/use-conversation-name-context-menu.js.map +1 -1
  493. package/dist/hooks/use-drag-resize.cjs +1 -1
  494. package/dist/hooks/use-drag-resize.cjs.map +1 -1
  495. package/dist/hooks/use-drag-resize.d.ts +8 -0
  496. package/dist/hooks/use-drag-resize.js +21 -18
  497. package/dist/hooks/use-drag-resize.js.map +1 -1
  498. package/dist/hooks/use-live-conversation-metrics.cjs +2 -0
  499. package/dist/hooks/use-live-conversation-metrics.cjs.map +1 -0
  500. package/dist/hooks/use-live-conversation-metrics.d.ts +18 -0
  501. package/dist/hooks/use-live-conversation-metrics.js +37 -0
  502. package/dist/hooks/use-live-conversation-metrics.js.map +1 -0
  503. package/dist/hooks/use-select-conversation-tab.cjs +1 -1
  504. package/dist/hooks/use-select-conversation-tab.cjs.map +1 -1
  505. package/dist/hooks/use-select-conversation-tab.js +2 -2
  506. package/dist/hooks/use-select-conversation-tab.js.map +1 -1
  507. package/dist/i18n/declaration.cjs +1 -1
  508. package/dist/i18n/declaration.cjs.map +1 -1
  509. package/dist/i18n/declaration.d.ts +27 -0
  510. package/dist/i18n/declaration.js +1 -1
  511. package/dist/i18n/declaration.js.map +1 -1
  512. package/dist/i18n/translation.cjs +2 -2
  513. package/dist/i18n/translation.cjs.map +1 -1
  514. package/dist/i18n/translation.js +474 -15
  515. package/dist/i18n/translation.js.map +1 -1
  516. package/dist/index.cjs +1 -1
  517. package/dist/index.js +28 -29
  518. package/dist/lib/index.cjs +1 -1
  519. package/dist/lib/index.js +0 -1
  520. package/dist/locales/ar/openhands.json +28 -1
  521. package/dist/locales/ca/openhands.json +28 -1
  522. package/dist/locales/de/openhands.json +28 -1
  523. package/dist/locales/en/openhands.json +28 -1
  524. package/dist/locales/es/openhands.json +28 -1
  525. package/dist/locales/fr/openhands.json +28 -1
  526. package/dist/locales/it/openhands.json +28 -1
  527. package/dist/locales/ja/openhands.json +28 -1
  528. package/dist/locales/ko-KR/openhands.json +28 -1
  529. package/dist/locales/no/openhands.json +28 -1
  530. package/dist/locales/pt/openhands.json +28 -1
  531. package/dist/locales/tr/openhands.json +28 -1
  532. package/dist/locales/uk/openhands.json +28 -1
  533. package/dist/locales/zh-CN/openhands.json +28 -1
  534. package/dist/locales/zh-TW/openhands.json +28 -1
  535. package/dist/node_modules/@microlink/react-json-view/dist/main.cjs +5 -5
  536. package/dist/node_modules/@microlink/react-json-view/dist/main.cjs.map +1 -1
  537. package/dist/node_modules/@microlink/react-json-view/dist/main.js +5194 -5187
  538. package/dist/node_modules/@microlink/react-json-view/dist/main.js.map +1 -1
  539. package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.cjs +2 -1
  540. package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.cjs.map +1 -0
  541. package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.js +21 -1
  542. package/dist/node_modules/@openhands/typescript-client/dist/client/desktop-client.js.map +1 -0
  543. package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.cjs +2 -1
  544. package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.cjs.map +1 -0
  545. package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.js +22 -1
  546. package/dist/node_modules/@openhands/typescript-client/dist/client/hooks-client.js.map +1 -0
  547. package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.cjs +2 -1
  548. package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.cjs.map +1 -0
  549. package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.js +33 -1
  550. package/dist/node_modules/@openhands/typescript-client/dist/client/meta-profiles-client.js.map +1 -0
  551. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs +1 -1
  552. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.cjs.map +1 -1
  553. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js +56 -22
  554. package/dist/node_modules/@openhands/typescript-client/dist/client/openhands-client.js.map +1 -1
  555. package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.cjs +1 -1
  556. package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.cjs.map +1 -1
  557. package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.js +3 -0
  558. package/dist/node_modules/@openhands/typescript-client/dist/client/profiles-client.js.map +1 -1
  559. package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.cjs +2 -1
  560. package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.cjs.map +1 -0
  561. package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.js +31 -1
  562. package/dist/node_modules/@openhands/typescript-client/dist/client/shared-client.js.map +1 -0
  563. package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.cjs +2 -1
  564. package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.cjs.map +1 -0
  565. package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.js +21 -1
  566. package/dist/node_modules/@openhands/typescript-client/dist/client/sub-agents-client.js.map +1 -0
  567. package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.cjs +2 -1
  568. package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.cjs.map +1 -0
  569. package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.js +21 -1
  570. package/dist/node_modules/@openhands/typescript-client/dist/client/tool-client.js.map +1 -0
  571. package/dist/node_modules/@openhands/typescript-client/dist/conversation/local-conversation.cjs.map +1 -1
  572. package/dist/node_modules/@openhands/typescript-client/dist/conversation/local-conversation.js.map +1 -1
  573. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs +1 -1
  574. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.cjs.map +1 -1
  575. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js +9 -5
  576. package/dist/node_modules/@openhands/typescript-client/dist/models/acp-providers.js.map +1 -1
  577. package/dist/node_modules/i18next-http-backend/esm/index.cjs +1 -1
  578. package/dist/node_modules/i18next-http-backend/esm/index.cjs.map +1 -1
  579. package/dist/node_modules/i18next-http-backend/esm/index.js +2 -2
  580. package/dist/node_modules/i18next-http-backend/esm/index.js.map +1 -1
  581. package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.cjs +2 -0
  582. package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.cjs.map +1 -0
  583. package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.js +31 -0
  584. package/dist/node_modules/lucide-react/dist/esm/icons/archive-restore.js.map +1 -0
  585. package/dist/node_modules/lucide-react/dist/esm/icons/archive.cjs +2 -0
  586. package/dist/node_modules/lucide-react/dist/esm/icons/archive.cjs.map +1 -0
  587. package/dist/node_modules/lucide-react/dist/esm/icons/archive.js +23 -0
  588. package/dist/node_modules/lucide-react/dist/esm/icons/archive.js.map +1 -0
  589. package/dist/node_modules/lucide-react/dist/esm/icons/gauge.cjs +2 -0
  590. package/dist/node_modules/lucide-react/dist/esm/icons/gauge.cjs.map +1 -0
  591. package/dist/node_modules/lucide-react/dist/esm/icons/gauge.js +12 -0
  592. package/dist/node_modules/lucide-react/dist/esm/icons/gauge.js.map +1 -0
  593. package/dist/node_modules/lucide-react/dist/esm/icons/minimize.cjs +2 -0
  594. package/dist/node_modules/lucide-react/dist/esm/icons/minimize.cjs.map +1 -0
  595. package/dist/node_modules/lucide-react/dist/esm/icons/minimize.js +23 -0
  596. package/dist/node_modules/lucide-react/dist/esm/icons/minimize.js.map +1 -0
  597. package/dist/node_modules/zustand/esm/middleware.cjs +3 -3
  598. package/dist/node_modules/zustand/esm/middleware.cjs.map +1 -1
  599. package/dist/node_modules/zustand/esm/middleware.js +33 -31
  600. package/dist/node_modules/zustand/esm/middleware.js.map +1 -1
  601. package/dist/package.cjs +1 -1
  602. package/dist/package.cjs.map +1 -1
  603. package/dist/package.js +17 -16
  604. package/dist/package.js.map +1 -1
  605. package/dist/routes/app-settings.cjs +1 -1
  606. package/dist/routes/app-settings.cjs.map +1 -1
  607. package/dist/routes/app-settings.js +94 -93
  608. package/dist/routes/app-settings.js.map +1 -1
  609. package/dist/routes/llm-settings.cjs +1 -1
  610. package/dist/routes/llm-settings.cjs.map +1 -1
  611. package/dist/routes/llm-settings.js +131 -119
  612. package/dist/routes/llm-settings.js.map +1 -1
  613. package/dist/routes/usage-tab.cjs +2 -0
  614. package/dist/routes/usage-tab.cjs.map +1 -0
  615. package/dist/routes/usage-tab.d.ts +2 -0
  616. package/dist/routes/usage-tab.js +10 -0
  617. package/dist/routes/usage-tab.js.map +1 -0
  618. package/dist/services/child-conversation-launch.cjs +1 -1
  619. package/dist/services/child-conversation-launch.cjs.map +1 -1
  620. package/dist/services/child-conversation-launch.js +11 -5
  621. package/dist/services/child-conversation-launch.js.map +1 -1
  622. package/dist/stores/archived-conversations-store.cjs +2 -0
  623. package/dist/stores/archived-conversations-store.cjs.map +1 -0
  624. package/dist/stores/archived-conversations-store.d.ts +24 -0
  625. package/dist/stores/archived-conversations-store.js +33 -0
  626. package/dist/stores/archived-conversations-store.js.map +1 -0
  627. package/dist/stores/conversation-panel-preferences-store.cjs +1 -1
  628. package/dist/stores/conversation-panel-preferences-store.cjs.map +1 -1
  629. package/dist/stores/conversation-panel-preferences-store.d.ts +3 -0
  630. package/dist/stores/conversation-panel-preferences-store.js +4 -0
  631. package/dist/stores/conversation-panel-preferences-store.js.map +1 -1
  632. package/dist/stores/conversation-store.cjs.map +1 -1
  633. package/dist/stores/conversation-store.d.ts +1 -1
  634. package/dist/stores/conversation-store.js.map +1 -1
  635. package/dist/stores/metrics-store.cjs +1 -1
  636. package/dist/stores/metrics-store.cjs.map +1 -1
  637. package/dist/stores/metrics-store.d.ts +1 -0
  638. package/dist/stores/metrics-store.js +7 -4
  639. package/dist/stores/metrics-store.js.map +1 -1
  640. package/dist/types/agent-server/core/events/condensation-event.d.ts +3 -0
  641. package/dist/types/agent-server/core/events/conversation-state-event.d.ts +4 -6
  642. package/dist/types/agent-server/type-guards.cjs +1 -1
  643. package/dist/types/agent-server/type-guards.cjs.map +1 -1
  644. package/dist/types/agent-server/type-guards.d.ts +5 -0
  645. package/dist/types/agent-server/type-guards.js +3 -3
  646. package/dist/types/agent-server/type-guards.js.map +1 -1
  647. package/dist/utils/conversation-local-storage.cjs +1 -1
  648. package/dist/utils/conversation-local-storage.cjs.map +1 -1
  649. package/dist/utils/conversation-local-storage.js +2 -1
  650. package/dist/utils/conversation-local-storage.js.map +1 -1
  651. package/dist/utils/format-model-name.cjs +1 -1
  652. package/dist/utils/format-model-name.cjs.map +1 -1
  653. package/dist/utils/format-model-name.d.ts +11 -0
  654. package/dist/utils/format-model-name.js +11 -3
  655. package/dist/utils/format-model-name.js.map +1 -1
  656. package/dist/utils/format-token-count.cjs +2 -0
  657. package/dist/utils/format-token-count.cjs.map +1 -0
  658. package/dist/utils/format-token-count.d.ts +3 -0
  659. package/dist/utils/format-token-count.js +19 -0
  660. package/dist/utils/format-token-count.js.map +1 -0
  661. package/dist/utils/hover-reveal-classes.cjs +2 -0
  662. package/dist/utils/hover-reveal-classes.cjs.map +1 -0
  663. package/dist/utils/hover-reveal-classes.d.ts +34 -0
  664. package/dist/utils/hover-reveal-classes.js +41 -0
  665. package/dist/utils/hover-reveal-classes.js.map +1 -0
  666. package/dist/utils/is-markdown-file-path.cjs +2 -0
  667. package/dist/utils/is-markdown-file-path.cjs.map +1 -0
  668. package/dist/utils/is-markdown-file-path.d.ts +4 -0
  669. package/dist/utils/is-markdown-file-path.js +14 -0
  670. package/dist/utils/is-markdown-file-path.js.map +1 -0
  671. package/dist/utils/mcp-marketplace-utils.cjs +1 -1
  672. package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
  673. package/dist/utils/mcp-marketplace-utils.d.ts +7 -0
  674. package/dist/utils/mcp-marketplace-utils.js +19 -16
  675. package/dist/utils/mcp-marketplace-utils.js.map +1 -1
  676. package/dist/utils/transcript-export/index.cjs +3 -3
  677. package/dist/utils/transcript-export/index.cjs.map +1 -1
  678. package/dist/utils/transcript-export/index.js +12 -12
  679. package/dist/utils/transcript-export/index.js.map +1 -1
  680. package/dist/utils/transcript-export/load-complete-events.cjs +1 -1
  681. package/dist/utils/transcript-export/load-complete-events.cjs.map +1 -1
  682. package/dist/utils/transcript-export/load-complete-events.js +4 -4
  683. package/dist/utils/transcript-export/load-complete-events.js.map +1 -1
  684. package/dist/utils/workspace-relative-path.cjs +2 -0
  685. package/dist/utils/workspace-relative-path.cjs.map +1 -0
  686. package/dist/utils/workspace-relative-path.d.ts +10 -0
  687. package/dist/utils/workspace-relative-path.js +22 -0
  688. package/dist/utils/workspace-relative-path.js.map +1 -0
  689. package/package.json +17 -16
  690. package/scripts/check-sdk-version-sync.mjs +6 -6
  691. package/scripts/dev-process-utils.mjs +6 -1
  692. package/scripts/dev-safe.mjs +57 -2
  693. package/build/assets/active-backend-context-BBvP-bI2.js +0 -2
  694. package/build/assets/agent-profiles-settings-DqoS7RL3.js +0 -1
  695. package/build/assets/agent-server-conversation-service.api-0RztSdJJ.js +0 -86
  696. package/build/assets/agent-settings-BJHryp65.js +0 -1
  697. package/build/assets/app-settings-r1RUbgGi.js +0 -1
  698. package/build/assets/backend-form-modal-OroTqnAv.js +0 -1
  699. package/build/assets/bot-DuN83i3p.js +0 -1
  700. package/build/assets/browser--eoQOo4M.js +0 -6
  701. package/build/assets/check-DLOKoFU9.js +0 -1
  702. package/build/assets/chevron-down-CnIbtM6i.js +0 -1
  703. package/build/assets/circle-check-CxCYJrpZ.js +0 -1
  704. package/build/assets/conversation-BUzBZAc-.js +0 -90
  705. package/build/assets/conversation-panel-pzAKsSDb.js +0 -1
  706. package/build/assets/conversation-pzAKsSDb.js +0 -1
  707. package/build/assets/conversation-store-B8Eahyeg.js +0 -6
  708. package/build/assets/external-link-zWbg5KXS.js +0 -1
  709. package/build/assets/files-tab-BzofBmF4.js +0 -1
  710. package/build/assets/git-provider-icon-BLMlwy02.js +0 -1
  711. package/build/assets/git-repo-dropdown-B_PTq4ol.js +0 -1
  712. package/build/assets/home-r89Vj2td.js +0 -1
  713. package/build/assets/index-home-r89Vj2td.js +0 -1
  714. package/build/assets/llm-not-configured-banner-CwKu8C6g.js +0 -27
  715. package/build/assets/llm-settings-BJotLQND.js +0 -1
  716. package/build/assets/llm-settings-CDM-5H2A.js +0 -1
  717. package/build/assets/llm-subscription-service-7eVfDIE1.js +0 -1
  718. package/build/assets/loader-circle-C5AnEN8r.js +0 -1
  719. package/build/assets/manifest-2a36a8f8.js +0 -1
  720. package/build/assets/markdown-renderer-BiiiIznl.js +0 -8
  721. package/build/assets/mcp-marketplace-utils-Dr_HG_ol.js +0 -1
  722. package/build/assets/messages-D1cbVhRK.js +0 -40
  723. package/build/assets/pencil-Bl3GWhgq.js +0 -1
  724. package/build/assets/plus-CtzlyAoF.js +0 -1
  725. package/build/assets/recommended-automations-launcher-BbJAJVED.js +0 -1
  726. package/build/assets/refresh-cw-B9GhC3QC.js +0 -1
  727. package/build/assets/root-BfM_kC_d.css +0 -1
  728. package/build/assets/root-gstBEjty.js +0 -2
  729. package/build/assets/root-layout-BIAFLP9p.js +0 -2
  730. package/build/assets/search-CYaiKHRp.js +0 -1
  731. package/build/assets/shared-conversation-DIxZjElr.js +0 -1
  732. package/build/assets/shield-check-D2cpEpv3.js +0 -1
  733. package/build/assets/trash-2-CzDVN-Iw.js +0 -1
  734. package/build/assets/use-create-conversation-DWaSVUOB.js +0 -1
  735. package/build/assets/use-is-authed-Bka89Xmm.js +0 -1
  736. package/build/assets/use-llm-profiles-CU8ah1pz.js +0 -1
  737. package/build/assets/use-save-agent-profile-DgI_Uz9a.js +0 -1
  738. package/build/assets/utils-DPQfkd-7.js +0 -1
  739. package/build/assets/vendor~index-home~home~conversation-panel~conversation-DiXf0dkj.js +0 -13
  740. package/build/assets/x-RYDBg-e2.js +0 -1
  741. package/build/assets/zap-tbKDzCe3.js +0 -1
  742. package/dist/components/features/conversation/metrics-modal/context-window-section.cjs +0 -2
  743. package/dist/components/features/conversation/metrics-modal/context-window-section.cjs.map +0 -1
  744. package/dist/components/features/conversation/metrics-modal/context-window-section.d.ts +0 -6
  745. package/dist/components/features/conversation/metrics-modal/context-window-section.js +0 -46
  746. package/dist/components/features/conversation/metrics-modal/context-window-section.js.map +0 -1
  747. package/dist/components/features/conversation/metrics-modal/empty-state.cjs +0 -2
  748. package/dist/components/features/conversation/metrics-modal/empty-state.cjs.map +0 -1
  749. package/dist/components/features/conversation/metrics-modal/empty-state.d.ts +0 -1
  750. package/dist/components/features/conversation/metrics-modal/empty-state.js +0 -18
  751. package/dist/components/features/conversation/metrics-modal/empty-state.js.map +0 -1
  752. package/dist/components/features/conversation/metrics-modal/metrics-modal-header.cjs +0 -2
  753. package/dist/components/features/conversation/metrics-modal/metrics-modal-header.cjs.map +0 -1
  754. package/dist/components/features/conversation/metrics-modal/metrics-modal-header.d.ts +0 -5
  755. package/dist/components/features/conversation/metrics-modal/metrics-modal-header.js +0 -20
  756. package/dist/components/features/conversation/metrics-modal/metrics-modal-header.js.map +0 -1
  757. package/dist/components/features/conversation/metrics-modal/metrics-modal.cjs +0 -2
  758. package/dist/components/features/conversation/metrics-modal/metrics-modal.cjs.map +0 -1
  759. package/dist/components/features/conversation/metrics-modal/metrics-modal.d.ts +0 -6
  760. package/dist/components/features/conversation/metrics-modal/metrics-modal.js +0 -57
  761. package/dist/components/features/conversation/metrics-modal/metrics-modal.js.map +0 -1
  762. package/dist/icons/u-credit-card.cjs +0 -2
  763. package/dist/icons/u-credit-card.cjs.map +0 -1
  764. package/dist/icons/u-credit-card.js +0 -21
  765. package/dist/icons/u-credit-card.js.map +0 -1
  766. /package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~cy4jtuc2-rfV8mQ9m.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dh9v73sa-rfV8mQ9m.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-store.js","names":[],"sources":["../../src/stores/conversation-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport {\n getConversationState,\n setConversationState,\n} from \"#/utils/conversation-local-storage\";\n\nexport type ConversationTab =\n | \"files\"\n | \"browser\"\n | \"terminal\"\n | \"planner\"\n | \"tasklist\";\n\nexport type ConversationMode = \"code\" | \"plan\";\n\nexport interface IMessageToSend {\n text: string;\n timestamp: number;\n}\n\ninterface ConversationState {\n isRightPanelShown: boolean;\n selectedTab: ConversationTab | null;\n images: File[];\n files: File[];\n /** Image file names (e.g. pasted screenshots) to send via file upload instead of vision embed. */\n imagesMarkedUploadAsFile: string[];\n /** Image file names attached in chat (controls per-image upload-as-file UI). */\n pastedImageNames: string[];\n loadingFiles: string[]; // File names currently being processed\n loadingImages: string[]; // Image names currently being processed\n messageToSend: IMessageToSend | null;\n /** One-shot restore request consumed by the chat input when empty. */\n messageRestoreIfEmpty: IMessageToSend | null;\n shouldShownAgentLoading: boolean;\n submittedMessage: string | null;\n shouldHideSuggestions: boolean; // New state to hide suggestions when input expands\n hasRightPanelToggled: boolean;\n planContent: string | null;\n conversationMode: ConversationMode;\n subConversationTaskId: string | null; // Task ID for sub-conversation creation\n}\n\ninterface ConversationActions {\n setIsRightPanelShown: (isRightPanelShown: boolean) => void;\n setSelectedTab: (selectedTab: ConversationTab | null) => void;\n setShouldShownAgentLoading: (shouldShownAgentLoading: boolean) => void;\n setShouldHideSuggestions: (shouldHideSuggestions: boolean) => void;\n addImages: (images: File[]) => void;\n addFiles: (files: File[]) => void;\n toggleImageUploadAsFile: (fileName: string) => void;\n markImagesAsPasted: (fileNames: string[]) => void;\n removeImage: (index: number) => void;\n removeFile: (index: number) => void;\n clearImages: () => void;\n clearFiles: () => void;\n clearAllFiles: () => void;\n addFileLoading: (fileName: string) => void;\n removeFileLoading: (fileName: string) => void;\n addImageLoading: (imageName: string) => void;\n removeImageLoading: (imageName: string) => void;\n clearAllLoading: () => void;\n setMessageToSend: (text: string) => void;\n clearMessageToSend: () => void;\n restoreMessageToInputIfEmpty: (text: string) => void;\n clearMessageRestoreIfEmpty: () => void;\n setSubmittedMessage: (message: string | null) => void;\n resetConversationState: () => void;\n setHasRightPanelToggled: (hasRightPanelToggled: boolean) => void;\n setConversationMode: (conversationMode: ConversationMode) => void;\n setSubConversationTaskId: (taskId: string | null) => void;\n setPlanContent: (planContent: string | null) => void;\n}\n\ntype ConversationStore = ConversationState & ConversationActions;\n\nconst getConversationIdFromLocation = (): string | null => {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n const match = window.location.pathname.match(/\\/conversations\\/([^/]+)/);\n return match ? match[1] : null;\n};\n\nconst getInitialConversationMode = (): ConversationMode => {\n if (typeof window === \"undefined\") {\n return \"code\";\n }\n\n const conversationId = getConversationIdFromLocation();\n if (!conversationId) {\n return \"code\";\n }\n\n const state = getConversationState(conversationId);\n return state.conversationMode;\n};\n\nexport const useConversationStore = create<ConversationStore>()(\n devtools(\n (set) => ({\n // Initial state.\n //\n // The right-side drawer (`isRightPanelShown` / `hasRightPanelToggled`)\n // is intentionally *session-only* state: it always starts closed on\n // app load (or on opening a fresh/existing conversation after a\n // restart), but it survives in-app navigation because the Zustand\n // store stays alive across React Router transitions. Persisting the\n // open/closed state in localStorage made the panel feel sticky in\n // a way users didn't expect — they want a clean, focused chat view\n // when they come back to the app and only want the panel back when\n // they themselves opened it during the current session.\n isRightPanelShown: false,\n selectedTab: \"files\" as ConversationTab,\n images: [],\n files: [],\n imagesMarkedUploadAsFile: [],\n pastedImageNames: [],\n loadingFiles: [],\n loadingImages: [],\n messageToSend: null,\n messageRestoreIfEmpty: null,\n shouldShownAgentLoading: false,\n submittedMessage: null,\n shouldHideSuggestions: false,\n hasRightPanelToggled: false,\n planContent: null,\n conversationMode: getInitialConversationMode(),\n subConversationTaskId: null,\n\n // Actions\n setIsRightPanelShown: (isRightPanelShown) =>\n set({ isRightPanelShown }, false, \"setIsRightPanelShown\"),\n\n setSelectedTab: (selectedTab) =>\n set({ selectedTab }, false, \"setSelectedTab\"),\n\n setShouldShownAgentLoading: (shouldShownAgentLoading) =>\n set({ shouldShownAgentLoading }, false, \"setShouldShownAgentLoading\"),\n\n setShouldHideSuggestions: (shouldHideSuggestions) =>\n set({ shouldHideSuggestions }, false, \"setShouldHideSuggestions\"),\n\n addImages: (images) =>\n set(\n (state) => ({ images: [...state.images, ...images] }),\n false,\n \"addImages\",\n ),\n\n addFiles: (files) =>\n set(\n (state) => ({ files: [...state.files, ...files] }),\n false,\n \"addFiles\",\n ),\n\n toggleImageUploadAsFile: (fileName) =>\n set(\n (state) => {\n const marked = new Set(state.imagesMarkedUploadAsFile);\n if (marked.has(fileName)) {\n marked.delete(fileName);\n } else {\n marked.add(fileName);\n }\n return { imagesMarkedUploadAsFile: [...marked] };\n },\n false,\n \"toggleImageUploadAsFile\",\n ),\n\n markImagesAsPasted: (fileNames) =>\n set(\n (state) => {\n const merged = new Set([...state.pastedImageNames, ...fileNames]);\n return { pastedImageNames: [...merged] };\n },\n false,\n \"markImagesAsPasted\",\n ),\n\n removeImage: (index) =>\n set(\n (state) => {\n const removed = state.images[index];\n const newImages = [...state.images];\n newImages.splice(index, 1);\n return {\n images: newImages,\n imagesMarkedUploadAsFile: removed\n ? state.imagesMarkedUploadAsFile.filter(\n (name) => name !== removed.name,\n )\n : state.imagesMarkedUploadAsFile,\n pastedImageNames: removed\n ? state.pastedImageNames.filter((name) => name !== removed.name)\n : state.pastedImageNames,\n };\n },\n false,\n \"removeImage\",\n ),\n\n removeFile: (index) =>\n set(\n (state) => {\n const newFiles = [...state.files];\n newFiles.splice(index, 1);\n return { files: newFiles };\n },\n false,\n \"removeFile\",\n ),\n\n clearImages: () => set({ images: [] }, false, \"clearImages\"),\n\n clearFiles: () => set({ files: [] }, false, \"clearFiles\"),\n\n clearAllFiles: () =>\n set(\n {\n images: [],\n files: [],\n imagesMarkedUploadAsFile: [],\n pastedImageNames: [],\n loadingFiles: [],\n loadingImages: [],\n },\n false,\n \"clearAllFiles\",\n ),\n\n addFileLoading: (fileName) =>\n set(\n (state) => {\n if (!state.loadingFiles.includes(fileName)) {\n return { loadingFiles: [...state.loadingFiles, fileName] };\n }\n return state;\n },\n false,\n \"addFileLoading\",\n ),\n\n removeFileLoading: (fileName) =>\n set(\n (state) => ({\n loadingFiles: state.loadingFiles.filter(\n (name) => name !== fileName,\n ),\n }),\n false,\n \"removeFileLoading\",\n ),\n\n addImageLoading: (imageName) =>\n set(\n (state) => {\n if (!state.loadingImages.includes(imageName)) {\n return { loadingImages: [...state.loadingImages, imageName] };\n }\n return state;\n },\n false,\n \"addImageLoading\",\n ),\n\n removeImageLoading: (imageName) =>\n set(\n (state) => ({\n loadingImages: state.loadingImages.filter(\n (name) => name !== imageName,\n ),\n }),\n false,\n \"removeImageLoading\",\n ),\n\n clearAllLoading: () =>\n set({ loadingFiles: [], loadingImages: [] }, false, \"clearAllLoading\"),\n\n setMessageToSend: (text) =>\n set(\n {\n messageToSend: {\n text,\n timestamp: Date.now(),\n },\n },\n false,\n \"setMessageToSend\",\n ),\n\n // One-shot consume: clear after the composer applies it, so a never-sent\n // value can't replay into another conversation's composer on remount.\n clearMessageToSend: () =>\n set({ messageToSend: null }, false, \"clearMessageToSend\"),\n\n restoreMessageToInputIfEmpty: (text) =>\n set(\n {\n messageRestoreIfEmpty: {\n text,\n timestamp: Date.now(),\n },\n },\n false,\n \"restoreMessageToInputIfEmpty\",\n ),\n\n clearMessageRestoreIfEmpty: () =>\n set(\n { messageRestoreIfEmpty: null },\n false,\n \"clearMessageRestoreIfEmpty\",\n ),\n\n setSubmittedMessage: (submittedMessage) =>\n set({ submittedMessage }, false, \"setSubmittedMessage\"),\n\n resetConversationState: () =>\n set(\n {\n shouldHideSuggestions: false,\n conversationMode: getInitialConversationMode(),\n subConversationTaskId: null,\n planContent: null,\n },\n false,\n \"resetConversationState\",\n ),\n\n setHasRightPanelToggled: (hasRightPanelToggled) =>\n set({ hasRightPanelToggled }, false, \"setHasRightPanelToggled\"),\n\n setConversationMode: (conversationMode) => {\n const conversationId = getConversationIdFromLocation();\n if (conversationId) {\n setConversationState(conversationId, { conversationMode });\n }\n set({ conversationMode }, false, \"setConversationMode\");\n },\n\n setSubConversationTaskId: (subConversationTaskId) =>\n set({ subConversationTaskId }, false, \"setSubConversationTaskId\"),\n\n setPlanContent: (planContent) =>\n set({ planContent }, false, \"setPlanContent\"),\n }),\n {\n name: \"conversation-store\",\n },\n ),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"conversation-store.js","names":[],"sources":["../../src/stores/conversation-store.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport { devtools } from \"zustand/middleware\";\nimport {\n getConversationState,\n setConversationState,\n} from \"#/utils/conversation-local-storage\";\n\nexport type ConversationTab =\n | \"files\"\n | \"browser\"\n | \"terminal\"\n | \"planner\"\n | \"tasklist\"\n | \"usage\";\n\nexport type ConversationMode = \"code\" | \"plan\";\n\nexport interface IMessageToSend {\n text: string;\n timestamp: number;\n}\n\ninterface ConversationState {\n isRightPanelShown: boolean;\n selectedTab: ConversationTab | null;\n images: File[];\n files: File[];\n /** Image file names (e.g. pasted screenshots) to send via file upload instead of vision embed. */\n imagesMarkedUploadAsFile: string[];\n /** Image file names attached in chat (controls per-image upload-as-file UI). */\n pastedImageNames: string[];\n loadingFiles: string[]; // File names currently being processed\n loadingImages: string[]; // Image names currently being processed\n messageToSend: IMessageToSend | null;\n /** One-shot restore request consumed by the chat input when empty. */\n messageRestoreIfEmpty: IMessageToSend | null;\n shouldShownAgentLoading: boolean;\n submittedMessage: string | null;\n shouldHideSuggestions: boolean; // New state to hide suggestions when input expands\n hasRightPanelToggled: boolean;\n planContent: string | null;\n conversationMode: ConversationMode;\n subConversationTaskId: string | null; // Task ID for sub-conversation creation\n}\n\ninterface ConversationActions {\n setIsRightPanelShown: (isRightPanelShown: boolean) => void;\n setSelectedTab: (selectedTab: ConversationTab | null) => void;\n setShouldShownAgentLoading: (shouldShownAgentLoading: boolean) => void;\n setShouldHideSuggestions: (shouldHideSuggestions: boolean) => void;\n addImages: (images: File[]) => void;\n addFiles: (files: File[]) => void;\n toggleImageUploadAsFile: (fileName: string) => void;\n markImagesAsPasted: (fileNames: string[]) => void;\n removeImage: (index: number) => void;\n removeFile: (index: number) => void;\n clearImages: () => void;\n clearFiles: () => void;\n clearAllFiles: () => void;\n addFileLoading: (fileName: string) => void;\n removeFileLoading: (fileName: string) => void;\n addImageLoading: (imageName: string) => void;\n removeImageLoading: (imageName: string) => void;\n clearAllLoading: () => void;\n setMessageToSend: (text: string) => void;\n clearMessageToSend: () => void;\n restoreMessageToInputIfEmpty: (text: string) => void;\n clearMessageRestoreIfEmpty: () => void;\n setSubmittedMessage: (message: string | null) => void;\n resetConversationState: () => void;\n setHasRightPanelToggled: (hasRightPanelToggled: boolean) => void;\n setConversationMode: (conversationMode: ConversationMode) => void;\n setSubConversationTaskId: (taskId: string | null) => void;\n setPlanContent: (planContent: string | null) => void;\n}\n\ntype ConversationStore = ConversationState & ConversationActions;\n\nconst getConversationIdFromLocation = (): string | null => {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n const match = window.location.pathname.match(/\\/conversations\\/([^/]+)/);\n return match ? match[1] : null;\n};\n\nconst getInitialConversationMode = (): ConversationMode => {\n if (typeof window === \"undefined\") {\n return \"code\";\n }\n\n const conversationId = getConversationIdFromLocation();\n if (!conversationId) {\n return \"code\";\n }\n\n const state = getConversationState(conversationId);\n return state.conversationMode;\n};\n\nexport const useConversationStore = create<ConversationStore>()(\n devtools(\n (set) => ({\n // Initial state.\n //\n // The right-side drawer (`isRightPanelShown` / `hasRightPanelToggled`)\n // is intentionally *session-only* state: it always starts closed on\n // app load (or on opening a fresh/existing conversation after a\n // restart), but it survives in-app navigation because the Zustand\n // store stays alive across React Router transitions. Persisting the\n // open/closed state in localStorage made the panel feel sticky in\n // a way users didn't expect — they want a clean, focused chat view\n // when they come back to the app and only want the panel back when\n // they themselves opened it during the current session.\n isRightPanelShown: false,\n selectedTab: \"files\" as ConversationTab,\n images: [],\n files: [],\n imagesMarkedUploadAsFile: [],\n pastedImageNames: [],\n loadingFiles: [],\n loadingImages: [],\n messageToSend: null,\n messageRestoreIfEmpty: null,\n shouldShownAgentLoading: false,\n submittedMessage: null,\n shouldHideSuggestions: false,\n hasRightPanelToggled: false,\n planContent: null,\n conversationMode: getInitialConversationMode(),\n subConversationTaskId: null,\n\n // Actions\n setIsRightPanelShown: (isRightPanelShown) =>\n set({ isRightPanelShown }, false, \"setIsRightPanelShown\"),\n\n setSelectedTab: (selectedTab) =>\n set({ selectedTab }, false, \"setSelectedTab\"),\n\n setShouldShownAgentLoading: (shouldShownAgentLoading) =>\n set({ shouldShownAgentLoading }, false, \"setShouldShownAgentLoading\"),\n\n setShouldHideSuggestions: (shouldHideSuggestions) =>\n set({ shouldHideSuggestions }, false, \"setShouldHideSuggestions\"),\n\n addImages: (images) =>\n set(\n (state) => ({ images: [...state.images, ...images] }),\n false,\n \"addImages\",\n ),\n\n addFiles: (files) =>\n set(\n (state) => ({ files: [...state.files, ...files] }),\n false,\n \"addFiles\",\n ),\n\n toggleImageUploadAsFile: (fileName) =>\n set(\n (state) => {\n const marked = new Set(state.imagesMarkedUploadAsFile);\n if (marked.has(fileName)) {\n marked.delete(fileName);\n } else {\n marked.add(fileName);\n }\n return { imagesMarkedUploadAsFile: [...marked] };\n },\n false,\n \"toggleImageUploadAsFile\",\n ),\n\n markImagesAsPasted: (fileNames) =>\n set(\n (state) => {\n const merged = new Set([...state.pastedImageNames, ...fileNames]);\n return { pastedImageNames: [...merged] };\n },\n false,\n \"markImagesAsPasted\",\n ),\n\n removeImage: (index) =>\n set(\n (state) => {\n const removed = state.images[index];\n const newImages = [...state.images];\n newImages.splice(index, 1);\n return {\n images: newImages,\n imagesMarkedUploadAsFile: removed\n ? state.imagesMarkedUploadAsFile.filter(\n (name) => name !== removed.name,\n )\n : state.imagesMarkedUploadAsFile,\n pastedImageNames: removed\n ? state.pastedImageNames.filter((name) => name !== removed.name)\n : state.pastedImageNames,\n };\n },\n false,\n \"removeImage\",\n ),\n\n removeFile: (index) =>\n set(\n (state) => {\n const newFiles = [...state.files];\n newFiles.splice(index, 1);\n return { files: newFiles };\n },\n false,\n \"removeFile\",\n ),\n\n clearImages: () => set({ images: [] }, false, \"clearImages\"),\n\n clearFiles: () => set({ files: [] }, false, \"clearFiles\"),\n\n clearAllFiles: () =>\n set(\n {\n images: [],\n files: [],\n imagesMarkedUploadAsFile: [],\n pastedImageNames: [],\n loadingFiles: [],\n loadingImages: [],\n },\n false,\n \"clearAllFiles\",\n ),\n\n addFileLoading: (fileName) =>\n set(\n (state) => {\n if (!state.loadingFiles.includes(fileName)) {\n return { loadingFiles: [...state.loadingFiles, fileName] };\n }\n return state;\n },\n false,\n \"addFileLoading\",\n ),\n\n removeFileLoading: (fileName) =>\n set(\n (state) => ({\n loadingFiles: state.loadingFiles.filter(\n (name) => name !== fileName,\n ),\n }),\n false,\n \"removeFileLoading\",\n ),\n\n addImageLoading: (imageName) =>\n set(\n (state) => {\n if (!state.loadingImages.includes(imageName)) {\n return { loadingImages: [...state.loadingImages, imageName] };\n }\n return state;\n },\n false,\n \"addImageLoading\",\n ),\n\n removeImageLoading: (imageName) =>\n set(\n (state) => ({\n loadingImages: state.loadingImages.filter(\n (name) => name !== imageName,\n ),\n }),\n false,\n \"removeImageLoading\",\n ),\n\n clearAllLoading: () =>\n set({ loadingFiles: [], loadingImages: [] }, false, \"clearAllLoading\"),\n\n setMessageToSend: (text) =>\n set(\n {\n messageToSend: {\n text,\n timestamp: Date.now(),\n },\n },\n false,\n \"setMessageToSend\",\n ),\n\n // One-shot consume: clear after the composer applies it, so a never-sent\n // value can't replay into another conversation's composer on remount.\n clearMessageToSend: () =>\n set({ messageToSend: null }, false, \"clearMessageToSend\"),\n\n restoreMessageToInputIfEmpty: (text) =>\n set(\n {\n messageRestoreIfEmpty: {\n text,\n timestamp: Date.now(),\n },\n },\n false,\n \"restoreMessageToInputIfEmpty\",\n ),\n\n clearMessageRestoreIfEmpty: () =>\n set(\n { messageRestoreIfEmpty: null },\n false,\n \"clearMessageRestoreIfEmpty\",\n ),\n\n setSubmittedMessage: (submittedMessage) =>\n set({ submittedMessage }, false, \"setSubmittedMessage\"),\n\n resetConversationState: () =>\n set(\n {\n shouldHideSuggestions: false,\n conversationMode: getInitialConversationMode(),\n subConversationTaskId: null,\n planContent: null,\n },\n false,\n \"resetConversationState\",\n ),\n\n setHasRightPanelToggled: (hasRightPanelToggled) =>\n set({ hasRightPanelToggled }, false, \"setHasRightPanelToggled\"),\n\n setConversationMode: (conversationMode) => {\n const conversationId = getConversationIdFromLocation();\n if (conversationId) {\n setConversationState(conversationId, { conversationMode });\n }\n set({ conversationMode }, false, \"setConversationMode\");\n },\n\n setSubConversationTaskId: (subConversationTaskId) =>\n set({ subConversationTaskId }, false, \"setSubConversationTaskId\"),\n\n setPlanContent: (planContent) =>\n set({ planContent }, false, \"setPlanContent\"),\n }),\n {\n name: \"conversation-store\",\n },\n ),\n);\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require("../_virtual/_rolldown/runtime.cjs");var e=require("../node_modules/zustand/esm/react.cjs").create(e=>({cost:null,max_budget_per_task:null,usage:null,setMetrics:t=>e(t)}));exports.default=e;
1
+ require("../_virtual/_rolldown/runtime.cjs");const e=require("../node_modules/zustand/esm/react.cjs");var t={cost:null,max_budget_per_task:null,usage:null},n=e.create(e=>({...t,setMetrics:t=>e(t),resetMetrics:()=>e(t)}));exports.default=n;
2
2
  //# sourceMappingURL=metrics-store.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"metrics-store.cjs","names":[],"sources":["../../src/stores/metrics-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\nexport interface MetricsState {\n cost: number | null;\n max_budget_per_task: number | null;\n usage: {\n prompt_tokens: number;\n completion_tokens: number;\n cache_read_tokens: number;\n cache_write_tokens: number;\n context_window: number;\n per_turn_token: number;\n } | null;\n}\n\nexport interface MetricsStore extends MetricsState {\n setMetrics: (metrics: MetricsState) => void;\n}\n\nconst useMetricsStore = create<MetricsStore>((set) => ({\n cost: null,\n max_budget_per_task: null,\n usage: null,\n setMetrics: (metrics) => set(metrics),\n}));\n\nexport default useMetricsStore;\n"],"mappings":"6CAmBA,IAAM,iDAAkB,EAAA,OAAsB,IAAS,CACrD,KAAM,KACN,oBAAqB,KACrB,MAAO,KACP,WAAa,GAAY,EAAI,CAAO,CACtC,EAAE"}
1
+ {"version":3,"file":"metrics-store.cjs","names":[],"sources":["../../src/stores/metrics-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\nexport interface MetricsState {\n cost: number | null;\n max_budget_per_task: number | null;\n usage: {\n prompt_tokens: number;\n completion_tokens: number;\n cache_read_tokens: number;\n cache_write_tokens: number;\n context_window: number;\n per_turn_token: number;\n } | null;\n}\n\nexport interface MetricsStore extends MetricsState {\n setMetrics: (metrics: MetricsState) => void;\n resetMetrics: () => void;\n}\n\nconst EMPTY_METRICS: MetricsState = {\n cost: null,\n max_budget_per_task: null,\n usage: null,\n};\n\nconst useMetricsStore = create<MetricsStore>((set) => ({\n ...EMPTY_METRICS,\n setMetrics: (metrics) => set(metrics),\n resetMetrics: () => set(EMPTY_METRICS),\n}));\n\n// Dev-only console handle for inspecting the live WS metrics while\n// debugging the usage meter (window.__OH_METRICS_STORE__.getState()).\n// Gated on import.meta.env.DEV so it never reaches production builds.\nif (typeof window !== \"undefined\" && import.meta.env.DEV) {\n (\n window as unknown as { __OH_METRICS_STORE__?: typeof useMetricsStore }\n ).__OH_METRICS_STORE__ = useMetricsStore;\n}\n\nexport default useMetricsStore;\n"],"mappings":"sGAoBA,IAAM,EAA8B,CAClC,KAAM,KACN,oBAAqB,KACrB,MAAO,IACT,EAEM,EAAkB,EAAA,OAAsB,IAAS,CACrD,GAAG,EACH,WAAa,GAAY,EAAI,CAAO,EACpC,iBAAoB,EAAI,CAAa,CACvC,EAAE"}
@@ -12,6 +12,7 @@ export interface MetricsState {
12
12
  }
13
13
  export interface MetricsStore extends MetricsState {
14
14
  setMetrics: (metrics: MetricsState) => void;
15
+ resetMetrics: () => void;
15
16
  }
16
17
  declare const useMetricsStore: import("zustand").UseBoundStore<import("zustand").StoreApi<MetricsStore>>;
17
18
  export default useMetricsStore;
@@ -1,12 +1,15 @@
1
1
  import { create as e } from "../node_modules/zustand/esm/react.js";
2
2
  //#region src/stores/metrics-store.ts
3
- var t = e((e) => ({
3
+ var t = {
4
4
  cost: null,
5
5
  max_budget_per_task: null,
6
- usage: null,
7
- setMetrics: (t) => e(t)
6
+ usage: null
7
+ }, n = e((e) => ({
8
+ ...t,
9
+ setMetrics: (t) => e(t),
10
+ resetMetrics: () => e(t)
8
11
  }));
9
12
  //#endregion
10
- export { t as default };
13
+ export { n as default };
11
14
 
12
15
  //# sourceMappingURL=metrics-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"metrics-store.js","names":[],"sources":["../../src/stores/metrics-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\nexport interface MetricsState {\n cost: number | null;\n max_budget_per_task: number | null;\n usage: {\n prompt_tokens: number;\n completion_tokens: number;\n cache_read_tokens: number;\n cache_write_tokens: number;\n context_window: number;\n per_turn_token: number;\n } | null;\n}\n\nexport interface MetricsStore extends MetricsState {\n setMetrics: (metrics: MetricsState) => void;\n}\n\nconst useMetricsStore = create<MetricsStore>((set) => ({\n cost: null,\n max_budget_per_task: null,\n usage: null,\n setMetrics: (metrics) => set(metrics),\n}));\n\nexport default useMetricsStore;\n"],"mappings":";;AAmBA,IAAM,IAAkB,GAAsB,OAAS;CACrD,MAAM;CACN,qBAAqB;CACrB,OAAO;CACP,aAAa,MAAY,EAAI,CAAO;AACtC,EAAE"}
1
+ {"version":3,"file":"metrics-store.js","names":[],"sources":["../../src/stores/metrics-store.ts"],"sourcesContent":["import { create } from \"zustand\";\n\nexport interface MetricsState {\n cost: number | null;\n max_budget_per_task: number | null;\n usage: {\n prompt_tokens: number;\n completion_tokens: number;\n cache_read_tokens: number;\n cache_write_tokens: number;\n context_window: number;\n per_turn_token: number;\n } | null;\n}\n\nexport interface MetricsStore extends MetricsState {\n setMetrics: (metrics: MetricsState) => void;\n resetMetrics: () => void;\n}\n\nconst EMPTY_METRICS: MetricsState = {\n cost: null,\n max_budget_per_task: null,\n usage: null,\n};\n\nconst useMetricsStore = create<MetricsStore>((set) => ({\n ...EMPTY_METRICS,\n setMetrics: (metrics) => set(metrics),\n resetMetrics: () => set(EMPTY_METRICS),\n}));\n\n// Dev-only console handle for inspecting the live WS metrics while\n// debugging the usage meter (window.__OH_METRICS_STORE__.getState()).\n// Gated on import.meta.env.DEV so it never reaches production builds.\nif (typeof window !== \"undefined\" && import.meta.env.DEV) {\n (\n window as unknown as { __OH_METRICS_STORE__?: typeof useMetricsStore }\n ).__OH_METRICS_STORE__ = useMetricsStore;\n}\n\nexport default useMetricsStore;\n"],"mappings":";;AAoBA,IAAM,IAA8B;CAClC,MAAM;CACN,qBAAqB;CACrB,OAAO;AACT,GAEM,IAAkB,GAAsB,OAAS;CACrD,GAAG;CACH,aAAa,MAAY,EAAI,CAAO;CACpC,oBAAoB,EAAI,CAAa;AACvC,EAAE"}
@@ -1,6 +1,7 @@
1
1
  import { EventID } from "../base/common";
2
2
  import { BaseEvent } from "../base/event";
3
3
  export interface CondensationEvent extends BaseEvent {
4
+ kind: "Condensation";
4
5
  /**
5
6
  * The source is always "environment" for condensation events
6
7
  */
@@ -19,12 +20,14 @@ export interface CondensationEvent extends BaseEvent {
19
20
  summary_offset?: number;
20
21
  }
21
22
  export interface CondensationRequestEvent extends BaseEvent {
23
+ kind: "CondensationRequest";
22
24
  /**
23
25
  * The source is always "environment" for condensation request events
24
26
  */
25
27
  source: "environment";
26
28
  }
27
29
  export interface CondensationSummaryEvent extends BaseEvent {
30
+ kind: "CondensationSummaryEvent";
28
31
  /**
29
32
  * The source is always "environment" for condensation summary events
30
33
  */
@@ -23,7 +23,7 @@ export interface LLMMetrics {
23
23
  model_name: string;
24
24
  accumulated_cost: number;
25
25
  max_budget_per_task: number | null;
26
- accumulated_token_usage: TokenUsage;
26
+ accumulated_token_usage: TokenUsage | null;
27
27
  costs: Array<{
28
28
  model: string;
29
29
  cost: number;
@@ -37,12 +37,10 @@ export interface LLMMetrics {
37
37
  token_usages: TokenUsage[];
38
38
  }
39
39
  /**
40
- * Usage metrics mapping for different components
40
+ * Usage metrics keyed by LLM usage id. The server uses arbitrary ids
41
+ * ("default", "condenser", "profile:<name>:<uuid>", …), not a fixed set.
41
42
  */
42
- export interface UsageToMetrics {
43
- agent: LLMMetrics;
44
- condenser: LLMMetrics;
45
- }
43
+ export type UsageToMetrics = Record<string, LLMMetrics>;
46
44
  /**
47
45
  * Stats containing usage metrics
48
46
  */
@@ -1,2 +1,2 @@
1
- require("../../_virtual/_rolldown/runtime.cjs"),require("../../constants/canvas-ui.cjs"),require("../../constants/child-conversation.cjs");function e(e){return typeof e==`object`&&!!e&&`id`in e&&`timestamp`in e&&`source`in e&&typeof e.id==`string`&&e.id.length>0&&typeof e.timestamp==`string`&&e.timestamp.length>0&&typeof e.source==`string`&&(e.source===`agent`||e.source===`user`||e.source===`environment`||e.source===`hook`)}var t=e=>e.source===`environment`&&`action_id`in e&&`observation`in e&&e.observation!==null&&typeof e.observation==`object`&&`kind`in e.observation,n=e=>e.source===`agent`&&`tool_name`in e&&`tool_call_id`in e&&`error`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`&&typeof e.error==`string`,r=e=>`llm_message`in e&&typeof e.llm_message==`object`&&e.llm_message!==null&&`role`in e.llm_message&&`content`in e.llm_message,i=e=>r(e)&&e.llm_message.role===`user`,a=e=>e.source===`agent`&&`action`in e&&e.action!==null&&typeof e.action==`object`&&`kind`in e.action&&`tool_name`in e&&`tool_call_id`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`,o=e=>a(e)&&(e.action.kind===`ExecuteBashAction`||e.action.kind===`TerminalAction`),s=e=>t(e)&&(e.observation.kind===`ExecuteBashObservation`||e.observation.kind===`TerminalObservation`),c=e=>t(e)&&e.observation.kind===`PlanningFileEditorObservation`,l=e=>t(e)&&e.observation.kind===`BrowserObservation`,u=e=>t(e)&&e.observation.kind===`SwitchLLMObservation`,d=e=>a(e)&&e.action.kind===`BrowserNavigateAction`,f=e=>a(e)&&(e.tool_name===`canvas_ui`||e.tool_name===`canvas_ui_control`),p=e=>a(e)&&e.tool_name===`launch_child_conversation`,m=e=>e.source===`agent`&&`system_prompt`in e&&`tools`in e&&typeof e.system_prompt==`object`&&Array.isArray(e.tools),h=e=>`kind`in e&&e.kind===`ConversationStateUpdateEvent`,g=e=>e.key===`full_state`,_=e=>e.key===`execution_status`,v=e=>e.key===`stats`,y=e=>e.key===`goal`,b=e=>`kind`in e&&e.kind===`ConversationErrorEvent`,x=e=>`kind`in e&&e.kind===`ServerErrorEvent`,S=e=>b(e)||x(e),C=e=>`kind`in e&&e.kind===`HookExecutionEvent`,w=e=>`kind`in e&&e.kind===`ACPToolCallEvent`,T=e=>`kind`in e&&e.kind===`StreamingDeltaEvent`;function E(t){return e(t)}exports.isACPToolCallEvent=w,exports.isActionEvent=a,exports.isAgentErrorEvent=n,exports.isAgentServerEvent=E,exports.isAgentStatusConversationStateUpdateEvent=_,exports.isBrowserNavigateActionEvent=d,exports.isBrowserObservationEvent=l,exports.isCanvasUIActionEvent=f,exports.isConversationStateUpdateEvent=h,exports.isDisplayableErrorEvent=S,exports.isExecuteBashActionEvent=o,exports.isExecuteBashObservationEvent=s,exports.isFullStateConversationStateUpdateEvent=g,exports.isGoalConversationStateUpdateEvent=y,exports.isHookExecutionEvent=C,exports.isLaunchChildConversationActionEvent=p,exports.isMessageEvent=r,exports.isObservationEvent=t,exports.isPlanningFileEditorObservationEvent=c,exports.isStatsConversationStateUpdateEvent=v,exports.isStreamingDeltaEvent=T,exports.isSwitchLLMObservationEvent=u,exports.isSystemPromptEvent=m,exports.isUserMessageEvent=i;
1
+ require("../../_virtual/_rolldown/runtime.cjs"),require("../../constants/canvas-ui.cjs"),require("../../constants/child-conversation.cjs");function e(e){return typeof e==`object`&&!!e&&`id`in e&&`timestamp`in e&&`source`in e&&typeof e.id==`string`&&e.id.length>0&&typeof e.timestamp==`string`&&e.timestamp.length>0&&typeof e.source==`string`&&(e.source===`agent`||e.source===`user`||e.source===`environment`||e.source===`hook`)}var t=e=>e.source===`environment`&&`action_id`in e&&`observation`in e&&e.observation!==null&&typeof e.observation==`object`&&`kind`in e.observation,n=e=>e.source===`agent`&&`tool_name`in e&&`tool_call_id`in e&&`error`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`&&typeof e.error==`string`,r=e=>`llm_message`in e&&typeof e.llm_message==`object`&&e.llm_message!==null&&`role`in e.llm_message&&`content`in e.llm_message,i=e=>r(e)&&e.llm_message.role===`user`,a=e=>e.source===`agent`&&`action`in e&&e.action!==null&&typeof e.action==`object`&&`kind`in e.action&&`tool_name`in e&&`tool_call_id`in e&&typeof e.tool_name==`string`&&typeof e.tool_call_id==`string`,o=e=>a(e)&&(e.action.kind===`ExecuteBashAction`||e.action.kind===`TerminalAction`),s=e=>t(e)&&(e.observation.kind===`ExecuteBashObservation`||e.observation.kind===`TerminalObservation`),c=e=>t(e)&&e.observation.kind===`PlanningFileEditorObservation`,l=e=>t(e)&&e.observation.kind===`BrowserObservation`,u=e=>t(e)&&e.observation.kind===`SwitchLLMObservation`,d=e=>a(e)&&e.action.kind===`BrowserNavigateAction`,f=e=>a(e)&&(e.tool_name===`canvas_ui`||e.tool_name===`canvas_ui_control`),p=e=>a(e)&&e.tool_name===`launch_child_conversation`,m=e=>e.source===`agent`&&`system_prompt`in e&&`tools`in e&&typeof e.system_prompt==`object`&&Array.isArray(e.tools),h=e=>`kind`in e&&e.kind===`ConversationStateUpdateEvent`,g=e=>e.key===`full_state`,_=e=>e.key===`execution_status`,v=e=>e.key===`stats`,y=e=>e.key===`goal`,b=e=>`kind`in e&&e.kind===`ConversationErrorEvent`,x=e=>`kind`in e&&e.kind===`ServerErrorEvent`,S=e=>b(e)||x(e),C=e=>`kind`in e&&e.kind===`HookExecutionEvent`,w=e=>`kind`in e&&e.kind===`ACPToolCallEvent`,T=e=>`kind`in e&&e.kind===`StreamingDeltaEvent`,E=e=>`kind`in e&&e.kind===`Condensation`;function D(t){return e(t)}exports.isACPToolCallEvent=w,exports.isActionEvent=a,exports.isAgentErrorEvent=n,exports.isAgentServerEvent=D,exports.isAgentStatusConversationStateUpdateEvent=_,exports.isBrowserNavigateActionEvent=d,exports.isBrowserObservationEvent=l,exports.isCanvasUIActionEvent=f,exports.isCondensationEvent=E,exports.isConversationStateUpdateEvent=h,exports.isDisplayableErrorEvent=S,exports.isExecuteBashActionEvent=o,exports.isExecuteBashObservationEvent=s,exports.isFullStateConversationStateUpdateEvent=g,exports.isGoalConversationStateUpdateEvent=y,exports.isHookExecutionEvent=C,exports.isLaunchChildConversationActionEvent=p,exports.isMessageEvent=r,exports.isObservationEvent=t,exports.isPlanningFileEditorObservationEvent=c,exports.isStatsConversationStateUpdateEvent=v,exports.isStreamingDeltaEvent=T,exports.isSwitchLLMObservationEvent=u,exports.isSystemPromptEvent=m,exports.isUserMessageEvent=i;
2
2
  //# sourceMappingURL=type-guards.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"type-guards.cjs","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n CANVAS_UI_CLIENT_TOOL_NAME,\n LEGACY_CANVAS_UI_TOOL_NAME,\n} from \"#/constants/canvas-ui\";\nimport { LAUNCH_CHILD_CONVERSATION_TOOL_NAME } from \"#/constants/child-conversation\";\n\nimport {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n LaunchChildConversationAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationStateUpdateEventGoal,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { StreamingDeltaEvent } from \"./core/events/streaming-delta-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for Canvas UI tool ActionEvents.\n *\n * Discriminating on tool_name supports legacy CanvasUIAction events and the\n * SDK-generated action kind without leaking that generated name here.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) &&\n (event.tool_name === LEGACY_CANVAS_UI_TOOL_NAME ||\n event.tool_name === CANVAS_UI_CLIENT_TOOL_NAME);\n\n/**\n * Type guard for launch-child-conversation tool ActionEvents.\n *\n * Discriminates on tool_name, like `isCanvasUIActionEvent`, so the\n * SDK-generated action kind stays contained in the constants module.\n */\nexport const isLaunchChildConversationActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<LaunchChildConversationAction> =>\n isActionEvent(event) &&\n event.tool_name === LAUNCH_CHILD_CONVERSATION_TOOL_NAME;\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\nexport const isGoalConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventGoal => event.key === \"goal\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\nexport const isStreamingDeltaEvent = (\n event: OpenHandsEvent,\n): event is StreamingDeltaEvent =>\n \"kind\" in event && event.kind === \"StreamingDeltaEvent\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":"2IA2CA,SAAgB,EAAY,EAAoC,CAC9D,OAEE,OAAO,GAAU,YADjB,GAEA,OAAQ,GACR,cAAe,GACf,WAAY,GACZ,OAAO,EAAM,IAAO,UACpB,EAAM,GAAG,OAAS,GAClB,OAAO,EAAM,WAAc,UAC3B,EAAM,UAAU,OAAS,GACzB,OAAO,EAAM,QAAW,WACvB,EAAM,SAAW,SAChB,EAAM,SAAW,QACjB,EAAM,SAAW,eACjB,EAAM,SAAW,OAEvB,CAKA,IAAa,EACX,GAEA,EAAM,SAAW,eACjB,cAAe,GACf,gBAAiB,GACjB,EAAM,cAAgB,MACtB,OAAO,EAAM,aAAgB,UAC7B,SAAU,EAAM,YAKL,EACX,GAEA,EAAM,SAAW,SACjB,cAAe,GACf,iBAAkB,GAClB,UAAW,GACX,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,UAC9B,OAAO,EAAM,OAAU,SAKZ,EAAkB,GAC7B,gBAAiB,GACjB,OAAO,EAAM,aAAgB,UAC7B,EAAM,cAAgB,MACtB,SAAU,EAAM,aAChB,YAAa,EAAM,YAKR,EACX,GAEA,EAAe,CAAK,GAAK,EAAM,YAAY,OAAS,OAKzC,EAAiB,GAC5B,EAAM,SAAW,SACjB,WAAY,GACZ,EAAM,SAAW,MACjB,OAAO,EAAM,QAAW,UACxB,SAAU,EAAM,QAChB,cAAe,GACf,iBAAkB,GAClB,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,SAKnB,EACX,GAEA,EAAc,CAAK,IAClB,EAAM,OAAO,OAAS,qBACrB,EAAM,OAAO,OAAS,kBAKb,EACX,GAEA,EAAmB,CAAK,IACvB,EAAM,YAAY,OAAS,0BAC1B,EAAM,YAAY,OAAS,uBAKlB,EACX,GAEA,EAAmB,CAAK,GACxB,EAAM,YAAY,OAAS,gCAKhB,EACX,GAEA,EAAmB,CAAK,GAAK,EAAM,YAAY,OAAS,qBAK7C,EACX,GAEA,EAAmB,CAAK,GACxB,EAAM,YAAY,OAAS,uBAKhB,EACX,GAEA,EAAc,CAAK,GAAK,EAAM,OAAO,OAAS,wBAQnC,EACX,GAEA,EAAc,CAAK,IAClB,EAAM,YAAA,aACL,EAAM,YAAA,qBAQG,EACX,GAEA,EAAc,CAAK,GACnB,EAAM,YAAA,4BAKK,EACX,GAEA,EAAM,SAAW,SACjB,kBAAmB,GACnB,UAAW,GACX,OAAO,EAAM,eAAkB,UAC/B,MAAM,QAAQ,EAAM,KAAK,EAKd,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,+BAEvB,EACX,GACmD,EAAM,MAAQ,aAEtD,EACX,GAEA,EAAM,MAAQ,mBAEH,EACX,GAC+C,EAAM,MAAQ,QAElD,EACX,GAC8C,EAAM,MAAQ,OAKjD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,yBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAMvB,EAA2B,GACtC,EAAyB,CAAK,GAAK,EAAmB,CAAK,EAKhD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,qBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAEvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,sBAUpC,SAAgB,EAAmB,EAAyC,CAC1E,OAAO,EAAY,CAAK,CAC1B"}
1
+ {"version":3,"file":"type-guards.cjs","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n CANVAS_UI_CLIENT_TOOL_NAME,\n LEGACY_CANVAS_UI_TOOL_NAME,\n} from \"#/constants/canvas-ui\";\nimport { LAUNCH_CHILD_CONVERSATION_TOOL_NAME } from \"#/constants/child-conversation\";\n\nimport {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n LaunchChildConversationAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationStateUpdateEventGoal,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { StreamingDeltaEvent } from \"./core/events/streaming-delta-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\nimport { CondensationEvent } from \"./core/events/condensation-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for Canvas UI tool ActionEvents.\n *\n * Discriminating on tool_name supports legacy CanvasUIAction events and the\n * SDK-generated action kind without leaking that generated name here.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) &&\n (event.tool_name === LEGACY_CANVAS_UI_TOOL_NAME ||\n event.tool_name === CANVAS_UI_CLIENT_TOOL_NAME);\n\n/**\n * Type guard for launch-child-conversation tool ActionEvents.\n *\n * Discriminates on tool_name, like `isCanvasUIActionEvent`, so the\n * SDK-generated action kind stays contained in the constants module.\n */\nexport const isLaunchChildConversationActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<LaunchChildConversationAction> =>\n isActionEvent(event) &&\n event.tool_name === LAUNCH_CHILD_CONVERSATION_TOOL_NAME;\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\nexport const isGoalConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventGoal => event.key === \"goal\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\nexport const isStreamingDeltaEvent = (\n event: OpenHandsEvent,\n): event is StreamingDeltaEvent =>\n \"kind\" in event && event.kind === \"StreamingDeltaEvent\";\n\n/**\n * Type guard for condensation completion events (history was compacted).\n */\nexport const isCondensationEvent = (\n event: OpenHandsEvent,\n): event is CondensationEvent =>\n \"kind\" in event && event.kind === \"Condensation\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":"2IA4CA,SAAgB,EAAY,EAAoC,CAC9D,OAEE,OAAO,GAAU,YADjB,GAEA,OAAQ,GACR,cAAe,GACf,WAAY,GACZ,OAAO,EAAM,IAAO,UACpB,EAAM,GAAG,OAAS,GAClB,OAAO,EAAM,WAAc,UAC3B,EAAM,UAAU,OAAS,GACzB,OAAO,EAAM,QAAW,WACvB,EAAM,SAAW,SAChB,EAAM,SAAW,QACjB,EAAM,SAAW,eACjB,EAAM,SAAW,OAEvB,CAKA,IAAa,EACX,GAEA,EAAM,SAAW,eACjB,cAAe,GACf,gBAAiB,GACjB,EAAM,cAAgB,MACtB,OAAO,EAAM,aAAgB,UAC7B,SAAU,EAAM,YAKL,EACX,GAEA,EAAM,SAAW,SACjB,cAAe,GACf,iBAAkB,GAClB,UAAW,GACX,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,UAC9B,OAAO,EAAM,OAAU,SAKZ,EAAkB,GAC7B,gBAAiB,GACjB,OAAO,EAAM,aAAgB,UAC7B,EAAM,cAAgB,MACtB,SAAU,EAAM,aAChB,YAAa,EAAM,YAKR,EACX,GAEA,EAAe,CAAK,GAAK,EAAM,YAAY,OAAS,OAKzC,EAAiB,GAC5B,EAAM,SAAW,SACjB,WAAY,GACZ,EAAM,SAAW,MACjB,OAAO,EAAM,QAAW,UACxB,SAAU,EAAM,QAChB,cAAe,GACf,iBAAkB,GAClB,OAAO,EAAM,WAAc,UAC3B,OAAO,EAAM,cAAiB,SAKnB,EACX,GAEA,EAAc,CAAK,IAClB,EAAM,OAAO,OAAS,qBACrB,EAAM,OAAO,OAAS,kBAKb,EACX,GAEA,EAAmB,CAAK,IACvB,EAAM,YAAY,OAAS,0BAC1B,EAAM,YAAY,OAAS,uBAKlB,EACX,GAEA,EAAmB,CAAK,GACxB,EAAM,YAAY,OAAS,gCAKhB,EACX,GAEA,EAAmB,CAAK,GAAK,EAAM,YAAY,OAAS,qBAK7C,EACX,GAEA,EAAmB,CAAK,GACxB,EAAM,YAAY,OAAS,uBAKhB,EACX,GAEA,EAAc,CAAK,GAAK,EAAM,OAAO,OAAS,wBAQnC,EACX,GAEA,EAAc,CAAK,IAClB,EAAM,YAAA,aACL,EAAM,YAAA,qBAQG,EACX,GAEA,EAAc,CAAK,GACnB,EAAM,YAAA,4BAKK,EACX,GAEA,EAAM,SAAW,SACjB,kBAAmB,GACnB,UAAW,GACX,OAAO,EAAM,eAAkB,UAC/B,MAAM,QAAQ,EAAM,KAAK,EAKd,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,+BAEvB,EACX,GACmD,EAAM,MAAQ,aAEtD,EACX,GAEA,EAAM,MAAQ,mBAEH,EACX,GAC+C,EAAM,MAAQ,QAElD,EACX,GAC8C,EAAM,MAAQ,OAKjD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,yBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAMvB,EAA2B,GACtC,EAAyB,CAAK,GAAK,EAAmB,CAAK,EAKhD,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,qBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,mBAEvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,sBAKvB,EACX,GAEA,SAAU,GAAS,EAAM,OAAS,eAUpC,SAAgB,EAAmB,EAAyC,CAC1E,OAAO,EAAY,CAAK,CAC1B"}
@@ -7,6 +7,7 @@ import { HookExecutionEvent } from "./core/events/hook-execution-event";
7
7
  import { ACPToolCallEvent } from "./core/events/acp-tool-call-event";
8
8
  import { StreamingDeltaEvent } from "./core/events/streaming-delta-event";
9
9
  import { SystemPromptEvent } from "./core/events/system-event";
10
+ import { CondensationEvent } from "./core/events/condensation-event";
10
11
  /**
11
12
  * Type guard to check if an unknown value is a valid BaseEvent
12
13
  * @param value - The value to check
@@ -105,6 +106,10 @@ export declare const isHookExecutionEvent: (event: OpenHandsEvent) => event is H
105
106
  */
106
107
  export declare const isACPToolCallEvent: (event: OpenHandsEvent) => event is ACPToolCallEvent;
107
108
  export declare const isStreamingDeltaEvent: (event: OpenHandsEvent) => event is StreamingDeltaEvent;
109
+ /**
110
+ * Type guard for condensation completion events (history was compacted).
111
+ */
112
+ export declare const isCondensationEvent: (event: OpenHandsEvent) => event is CondensationEvent;
108
113
  /**
109
114
  * Type guard to check if an event is an agent-server OpenHandsEvent.
110
115
  * Uses isBaseEvent to validate the complete event structure.
@@ -4,11 +4,11 @@ import "../../constants/child-conversation.js";
4
4
  function e(e) {
5
5
  return typeof e == "object" && !!e && "id" in e && "timestamp" in e && "source" in e && typeof e.id == "string" && e.id.length > 0 && typeof e.timestamp == "string" && e.timestamp.length > 0 && typeof e.source == "string" && (e.source === "agent" || e.source === "user" || e.source === "environment" || e.source === "hook");
6
6
  }
7
- var t = (e) => e.source === "environment" && "action_id" in e && "observation" in e && e.observation !== null && typeof e.observation == "object" && "kind" in e.observation, n = (e) => e.source === "agent" && "tool_name" in e && "tool_call_id" in e && "error" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string" && typeof e.error == "string", r = (e) => "llm_message" in e && typeof e.llm_message == "object" && e.llm_message !== null && "role" in e.llm_message && "content" in e.llm_message, i = (e) => r(e) && e.llm_message.role === "user", a = (e) => e.source === "agent" && "action" in e && e.action !== null && typeof e.action == "object" && "kind" in e.action && "tool_name" in e && "tool_call_id" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string", o = (e) => a(e) && (e.action.kind === "ExecuteBashAction" || e.action.kind === "TerminalAction"), s = (e) => t(e) && (e.observation.kind === "ExecuteBashObservation" || e.observation.kind === "TerminalObservation"), c = (e) => t(e) && e.observation.kind === "PlanningFileEditorObservation", l = (e) => t(e) && e.observation.kind === "BrowserObservation", u = (e) => t(e) && e.observation.kind === "SwitchLLMObservation", d = (e) => a(e) && e.action.kind === "BrowserNavigateAction", f = (e) => a(e) && (e.tool_name === "canvas_ui" || e.tool_name === "canvas_ui_control"), p = (e) => a(e) && e.tool_name === "launch_child_conversation", m = (e) => e.source === "agent" && "system_prompt" in e && "tools" in e && typeof e.system_prompt == "object" && Array.isArray(e.tools), h = (e) => "kind" in e && e.kind === "ConversationStateUpdateEvent", g = (e) => e.key === "full_state", _ = (e) => e.key === "execution_status", v = (e) => e.key === "stats", y = (e) => e.key === "goal", b = (e) => "kind" in e && e.kind === "ConversationErrorEvent", x = (e) => "kind" in e && e.kind === "ServerErrorEvent", S = (e) => b(e) || x(e), C = (e) => "kind" in e && e.kind === "HookExecutionEvent", w = (e) => "kind" in e && e.kind === "ACPToolCallEvent", T = (e) => "kind" in e && e.kind === "StreamingDeltaEvent";
8
- function E(t) {
7
+ var t = (e) => e.source === "environment" && "action_id" in e && "observation" in e && e.observation !== null && typeof e.observation == "object" && "kind" in e.observation, n = (e) => e.source === "agent" && "tool_name" in e && "tool_call_id" in e && "error" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string" && typeof e.error == "string", r = (e) => "llm_message" in e && typeof e.llm_message == "object" && e.llm_message !== null && "role" in e.llm_message && "content" in e.llm_message, i = (e) => r(e) && e.llm_message.role === "user", a = (e) => e.source === "agent" && "action" in e && e.action !== null && typeof e.action == "object" && "kind" in e.action && "tool_name" in e && "tool_call_id" in e && typeof e.tool_name == "string" && typeof e.tool_call_id == "string", o = (e) => a(e) && (e.action.kind === "ExecuteBashAction" || e.action.kind === "TerminalAction"), s = (e) => t(e) && (e.observation.kind === "ExecuteBashObservation" || e.observation.kind === "TerminalObservation"), c = (e) => t(e) && e.observation.kind === "PlanningFileEditorObservation", l = (e) => t(e) && e.observation.kind === "BrowserObservation", u = (e) => t(e) && e.observation.kind === "SwitchLLMObservation", d = (e) => a(e) && e.action.kind === "BrowserNavigateAction", f = (e) => a(e) && (e.tool_name === "canvas_ui" || e.tool_name === "canvas_ui_control"), p = (e) => a(e) && e.tool_name === "launch_child_conversation", m = (e) => e.source === "agent" && "system_prompt" in e && "tools" in e && typeof e.system_prompt == "object" && Array.isArray(e.tools), h = (e) => "kind" in e && e.kind === "ConversationStateUpdateEvent", g = (e) => e.key === "full_state", _ = (e) => e.key === "execution_status", v = (e) => e.key === "stats", y = (e) => e.key === "goal", b = (e) => "kind" in e && e.kind === "ConversationErrorEvent", x = (e) => "kind" in e && e.kind === "ServerErrorEvent", S = (e) => b(e) || x(e), C = (e) => "kind" in e && e.kind === "HookExecutionEvent", w = (e) => "kind" in e && e.kind === "ACPToolCallEvent", T = (e) => "kind" in e && e.kind === "StreamingDeltaEvent", E = (e) => "kind" in e && e.kind === "Condensation";
8
+ function D(t) {
9
9
  return e(t);
10
10
  }
11
11
  //#endregion
12
- export { w as isACPToolCallEvent, a as isActionEvent, n as isAgentErrorEvent, E as isAgentServerEvent, _ as isAgentStatusConversationStateUpdateEvent, d as isBrowserNavigateActionEvent, l as isBrowserObservationEvent, f as isCanvasUIActionEvent, h as isConversationStateUpdateEvent, S as isDisplayableErrorEvent, o as isExecuteBashActionEvent, s as isExecuteBashObservationEvent, g as isFullStateConversationStateUpdateEvent, y as isGoalConversationStateUpdateEvent, C as isHookExecutionEvent, p as isLaunchChildConversationActionEvent, r as isMessageEvent, t as isObservationEvent, c as isPlanningFileEditorObservationEvent, v as isStatsConversationStateUpdateEvent, T as isStreamingDeltaEvent, u as isSwitchLLMObservationEvent, m as isSystemPromptEvent, i as isUserMessageEvent };
12
+ export { w as isACPToolCallEvent, a as isActionEvent, n as isAgentErrorEvent, D as isAgentServerEvent, _ as isAgentStatusConversationStateUpdateEvent, d as isBrowserNavigateActionEvent, l as isBrowserObservationEvent, f as isCanvasUIActionEvent, E as isCondensationEvent, h as isConversationStateUpdateEvent, S as isDisplayableErrorEvent, o as isExecuteBashActionEvent, s as isExecuteBashObservationEvent, g as isFullStateConversationStateUpdateEvent, y as isGoalConversationStateUpdateEvent, C as isHookExecutionEvent, p as isLaunchChildConversationActionEvent, r as isMessageEvent, t as isObservationEvent, c as isPlanningFileEditorObservationEvent, v as isStatsConversationStateUpdateEvent, T as isStreamingDeltaEvent, u as isSwitchLLMObservationEvent, m as isSystemPromptEvent, i as isUserMessageEvent };
13
13
 
14
14
  //# sourceMappingURL=type-guards.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"type-guards.js","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n CANVAS_UI_CLIENT_TOOL_NAME,\n LEGACY_CANVAS_UI_TOOL_NAME,\n} from \"#/constants/canvas-ui\";\nimport { LAUNCH_CHILD_CONVERSATION_TOOL_NAME } from \"#/constants/child-conversation\";\n\nimport {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n LaunchChildConversationAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationStateUpdateEventGoal,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { StreamingDeltaEvent } from \"./core/events/streaming-delta-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for Canvas UI tool ActionEvents.\n *\n * Discriminating on tool_name supports legacy CanvasUIAction events and the\n * SDK-generated action kind without leaking that generated name here.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) &&\n (event.tool_name === LEGACY_CANVAS_UI_TOOL_NAME ||\n event.tool_name === CANVAS_UI_CLIENT_TOOL_NAME);\n\n/**\n * Type guard for launch-child-conversation tool ActionEvents.\n *\n * Discriminates on tool_name, like `isCanvasUIActionEvent`, so the\n * SDK-generated action kind stays contained in the constants module.\n */\nexport const isLaunchChildConversationActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<LaunchChildConversationAction> =>\n isActionEvent(event) &&\n event.tool_name === LAUNCH_CHILD_CONVERSATION_TOOL_NAME;\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\nexport const isGoalConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventGoal => event.key === \"goal\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\nexport const isStreamingDeltaEvent = (\n event: OpenHandsEvent,\n): event is StreamingDeltaEvent =>\n \"kind\" in event && event.kind === \"StreamingDeltaEvent\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":";;;AA2CA,SAAgB,EAAY,GAAoC;CAC9D,OAEE,OAAO,KAAU,cADjB,KAEA,QAAQ,KACR,eAAe,KACf,YAAY,KACZ,OAAO,EAAM,MAAO,YACpB,EAAM,GAAG,SAAS,KAClB,OAAO,EAAM,aAAc,YAC3B,EAAM,UAAU,SAAS,KACzB,OAAO,EAAM,UAAW,aACvB,EAAM,WAAW,WAChB,EAAM,WAAW,UACjB,EAAM,WAAW,iBACjB,EAAM,WAAW;AAEvB;AAKA,IAAa,KACX,MAEA,EAAM,WAAW,iBACjB,eAAe,KACf,iBAAiB,KACjB,EAAM,gBAAgB,QACtB,OAAO,EAAM,eAAgB,YAC7B,UAAU,EAAM,aAKL,KACX,MAEA,EAAM,WAAW,WACjB,eAAe,KACf,kBAAkB,KAClB,WAAW,KACX,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,YAC9B,OAAO,EAAM,SAAU,UAKZ,KAAkB,MAC7B,iBAAiB,KACjB,OAAO,EAAM,eAAgB,YAC7B,EAAM,gBAAgB,QACtB,UAAU,EAAM,eAChB,aAAa,EAAM,aAKR,KACX,MAEA,EAAe,CAAK,KAAK,EAAM,YAAY,SAAS,QAKzC,KAAiB,MAC5B,EAAM,WAAW,WACjB,YAAY,KACZ,EAAM,WAAW,QACjB,OAAO,EAAM,UAAW,YACxB,UAAU,EAAM,UAChB,eAAe,KACf,kBAAkB,KAClB,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,UAKnB,KACX,MAEA,EAAc,CAAK,MAClB,EAAM,OAAO,SAAS,uBACrB,EAAM,OAAO,SAAS,mBAKb,KACX,MAEA,EAAmB,CAAK,MACvB,EAAM,YAAY,SAAS,4BAC1B,EAAM,YAAY,SAAS,wBAKlB,KACX,MAEA,EAAmB,CAAK,KACxB,EAAM,YAAY,SAAS,iCAKhB,KACX,MAEA,EAAmB,CAAK,KAAK,EAAM,YAAY,SAAS,sBAK7C,KACX,MAEA,EAAmB,CAAK,KACxB,EAAM,YAAY,SAAS,wBAKhB,KACX,MAEA,EAAc,CAAK,KAAK,EAAM,OAAO,SAAS,yBAQnC,KACX,MAEA,EAAc,CAAK,MAClB,EAAM,cAAA,eACL,EAAM,cAAA,sBAQG,KACX,MAEA,EAAc,CAAK,KACnB,EAAM,cAAA,6BAKK,KACX,MAEA,EAAM,WAAW,WACjB,mBAAmB,KACnB,WAAW,KACX,OAAO,EAAM,iBAAkB,YAC/B,MAAM,QAAQ,EAAM,KAAK,GAKd,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,gCAEvB,KACX,MACmD,EAAM,QAAQ,cAEtD,KACX,MAEA,EAAM,QAAQ,oBAEH,KACX,MAC+C,EAAM,QAAQ,SAElD,KACX,MAC8C,EAAM,QAAQ,QAKjD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,0BAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAMvB,KAA2B,MACtC,EAAyB,CAAK,KAAK,EAAmB,CAAK,GAKhD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,sBAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAEvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS;AAUpC,SAAgB,EAAmB,GAAyC;CAC1E,OAAO,EAAY,CAAK;AAC1B"}
1
+ {"version":3,"file":"type-guards.js","names":[],"sources":["../../../src/types/agent-server/type-guards.ts"],"sourcesContent":["import {\n CANVAS_UI_CLIENT_TOOL_NAME,\n LEGACY_CANVAS_UI_TOOL_NAME,\n} from \"#/constants/canvas-ui\";\nimport { LAUNCH_CHILD_CONVERSATION_TOOL_NAME } from \"#/constants/child-conversation\";\n\nimport {\n OpenHandsEvent,\n ObservationEvent,\n BaseEvent,\n ExecuteBashAction,\n TerminalAction,\n ExecuteBashObservation,\n PlanningFileEditorObservation,\n TerminalObservation,\n BrowserObservation,\n BrowserNavigateAction,\n SwitchLLMObservation,\n CanvasUIAction,\n LaunchChildConversationAction,\n} from \"./core\";\nimport { AgentErrorEvent } from \"./core/events/observation-event\";\nimport { MessageEvent } from \"./core/events/message-event\";\nimport { ActionEvent } from \"./core/events/action-event\";\nimport {\n ConversationStateUpdateEvent,\n ConversationStateUpdateEventAgentStatus,\n ConversationStateUpdateEventFullState,\n ConversationStateUpdateEventStats,\n ConversationStateUpdateEventGoal,\n ConversationErrorEvent,\n ServerErrorEvent,\n} from \"./core/events/conversation-state-event\";\nimport { HookExecutionEvent } from \"./core/events/hook-execution-event\";\nimport { ACPToolCallEvent } from \"./core/events/acp-tool-call-event\";\nimport { StreamingDeltaEvent } from \"./core/events/streaming-delta-event\";\nimport { SystemPromptEvent } from \"./core/events/system-event\";\nimport { CondensationEvent } from \"./core/events/condensation-event\";\n\n/**\n * Type guard to check if an unknown value is a valid BaseEvent\n * @param value - The value to check\n * @returns true if the value is a valid BaseEvent\n */\nexport function isBaseEvent(value: unknown): value is BaseEvent {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"id\" in value &&\n \"timestamp\" in value &&\n \"source\" in value &&\n typeof value.id === \"string\" &&\n value.id.length > 0 &&\n typeof value.timestamp === \"string\" &&\n value.timestamp.length > 0 &&\n typeof value.source === \"string\" &&\n (value.source === \"agent\" ||\n value.source === \"user\" ||\n value.source === \"environment\" ||\n value.source === \"hook\")\n );\n}\n\n/**\n * Type guard function to check if an event is an observation event\n */\nexport const isObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent =>\n event.source === \"environment\" &&\n \"action_id\" in event &&\n \"observation\" in event &&\n event.observation !== null &&\n typeof event.observation === \"object\" &&\n \"kind\" in event.observation;\n\n/**\n * Type guard function to check if an event is an agent error event\n */\nexport const isAgentErrorEvent = (\n event: OpenHandsEvent,\n): event is AgentErrorEvent =>\n event.source === \"agent\" &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n \"error\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\" &&\n typeof event.error === \"string\";\n\n/**\n * Type guard function to check if an event is a message event (user or assistant)\n */\nexport const isMessageEvent = (event: OpenHandsEvent): event is MessageEvent =>\n \"llm_message\" in event &&\n typeof event.llm_message === \"object\" &&\n event.llm_message !== null &&\n \"role\" in event.llm_message &&\n \"content\" in event.llm_message;\n\n/**\n * Type guard function to check if an event is a user message event\n */\nexport const isUserMessageEvent = (\n event: OpenHandsEvent,\n): event is MessageEvent =>\n isMessageEvent(event) && event.llm_message.role === \"user\";\n\n/**\n * Type guard function to check if an event is an action event\n */\nexport const isActionEvent = (event: OpenHandsEvent): event is ActionEvent =>\n event.source === \"agent\" &&\n \"action\" in event &&\n event.action !== null &&\n typeof event.action === \"object\" &&\n \"kind\" in event.action &&\n \"tool_name\" in event &&\n \"tool_call_id\" in event &&\n typeof event.tool_name === \"string\" &&\n typeof event.tool_call_id === \"string\";\n\n/**\n * Type guard function to check if an action event is an ExecuteBashAction\n */\nexport const isExecuteBashActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<ExecuteBashAction | TerminalAction> =>\n isActionEvent(event) &&\n (event.action.kind === \"ExecuteBashAction\" ||\n event.action.kind === \"TerminalAction\");\n\n/**\n * Type guard function to check if an observation event contains terminal output\n */\nexport const isExecuteBashObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<ExecuteBashObservation | TerminalObservation> =>\n isObservationEvent(event) &&\n (event.observation.kind === \"ExecuteBashObservation\" ||\n event.observation.kind === \"TerminalObservation\");\n\n/**\n * Type guard function to check if an observation event is a PlanningFileEditorObservation\n */\nexport const isPlanningFileEditorObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<PlanningFileEditorObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"PlanningFileEditorObservation\";\n\n/**\n * Type guard function to check if an observation event is a BrowserObservation\n */\nexport const isBrowserObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<BrowserObservation> =>\n isObservationEvent(event) && event.observation.kind === \"BrowserObservation\";\n\n/**\n * Type guard function to check if an observation event is a SwitchLLMObservation\n */\nexport const isSwitchLLMObservationEvent = (\n event: OpenHandsEvent,\n): event is ObservationEvent<SwitchLLMObservation> =>\n isObservationEvent(event) &&\n event.observation.kind === \"SwitchLLMObservation\";\n\n/**\n * Type guard function to check if an action event is a BrowserNavigateAction\n */\nexport const isBrowserNavigateActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<BrowserNavigateAction> =>\n isActionEvent(event) && event.action.kind === \"BrowserNavigateAction\";\n\n/**\n * Type guard for Canvas UI tool ActionEvents.\n *\n * Discriminating on tool_name supports legacy CanvasUIAction events and the\n * SDK-generated action kind without leaking that generated name here.\n */\nexport const isCanvasUIActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<CanvasUIAction> =>\n isActionEvent(event) &&\n (event.tool_name === LEGACY_CANVAS_UI_TOOL_NAME ||\n event.tool_name === CANVAS_UI_CLIENT_TOOL_NAME);\n\n/**\n * Type guard for launch-child-conversation tool ActionEvents.\n *\n * Discriminates on tool_name, like `isCanvasUIActionEvent`, so the\n * SDK-generated action kind stays contained in the constants module.\n */\nexport const isLaunchChildConversationActionEvent = (\n event: OpenHandsEvent,\n): event is ActionEvent<LaunchChildConversationAction> =>\n isActionEvent(event) &&\n event.tool_name === LAUNCH_CHILD_CONVERSATION_TOOL_NAME;\n\n/**\n * Type guard function to check if an event is a system prompt event\n */\nexport const isSystemPromptEvent = (\n event: OpenHandsEvent,\n): event is SystemPromptEvent =>\n event.source === \"agent\" &&\n \"system_prompt\" in event &&\n \"tools\" in event &&\n typeof event.system_prompt === \"object\" &&\n Array.isArray(event.tools);\n\n/**\n * Type guard function to check if an event is a conversation state update event\n */\nexport const isConversationStateUpdateEvent = (\n event: OpenHandsEvent,\n): event is ConversationStateUpdateEvent =>\n \"kind\" in event && event.kind === \"ConversationStateUpdateEvent\";\n\nexport const isFullStateConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventFullState => event.key === \"full_state\";\n\nexport const isAgentStatusConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventAgentStatus =>\n event.key === \"execution_status\";\n\nexport const isStatsConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventStats => event.key === \"stats\";\n\nexport const isGoalConversationStateUpdateEvent = (\n event: ConversationStateUpdateEvent,\n): event is ConversationStateUpdateEventGoal => event.key === \"goal\";\n\n/**\n * Type guard function to check if an event is a conversation error event\n */\nexport const isConversationErrorEvent = (\n event: OpenHandsEvent,\n): event is ConversationErrorEvent =>\n \"kind\" in event && event.kind === \"ConversationErrorEvent\";\n\n/**\n * Type guard function to check if an event is a server error event\n */\nexport const isServerErrorEvent = (\n event: OpenHandsEvent,\n): event is ServerErrorEvent =>\n \"kind\" in event && event.kind === \"ServerErrorEvent\";\n\n/**\n * Type guard function to check if an event is a displayable error event\n * (ConversationErrorEvent or ServerErrorEvent) - both should show as error banners\n */\nexport const isDisplayableErrorEvent = (event: OpenHandsEvent): boolean =>\n isConversationErrorEvent(event) || isServerErrorEvent(event);\n\n/**\n * Type guard function to check if an event is a hook execution event\n */\nexport const isHookExecutionEvent = (\n event: OpenHandsEvent,\n): event is HookExecutionEvent =>\n \"kind\" in event && event.kind === \"HookExecutionEvent\";\n\n/**\n * Type guard function to check if an event is an ACP tool call event\n */\nexport const isACPToolCallEvent = (\n event: OpenHandsEvent,\n): event is ACPToolCallEvent =>\n \"kind\" in event && event.kind === \"ACPToolCallEvent\";\n\nexport const isStreamingDeltaEvent = (\n event: OpenHandsEvent,\n): event is StreamingDeltaEvent =>\n \"kind\" in event && event.kind === \"StreamingDeltaEvent\";\n\n/**\n * Type guard for condensation completion events (history was compacted).\n */\nexport const isCondensationEvent = (\n event: OpenHandsEvent,\n): event is CondensationEvent =>\n \"kind\" in event && event.kind === \"Condensation\";\n\n// =============================================================================\n// COMPATIBILITY TYPE GUARDS\n// =============================================================================\n\n/**\n * Type guard to check if an event is an agent-server OpenHandsEvent.\n * Uses isBaseEvent to validate the complete event structure.\n */\nexport function isAgentServerEvent(event: unknown): event is OpenHandsEvent {\n return isBaseEvent(event);\n}\n"],"mappings":";;;AA4CA,SAAgB,EAAY,GAAoC;CAC9D,OAEE,OAAO,KAAU,cADjB,KAEA,QAAQ,KACR,eAAe,KACf,YAAY,KACZ,OAAO,EAAM,MAAO,YACpB,EAAM,GAAG,SAAS,KAClB,OAAO,EAAM,aAAc,YAC3B,EAAM,UAAU,SAAS,KACzB,OAAO,EAAM,UAAW,aACvB,EAAM,WAAW,WAChB,EAAM,WAAW,UACjB,EAAM,WAAW,iBACjB,EAAM,WAAW;AAEvB;AAKA,IAAa,KACX,MAEA,EAAM,WAAW,iBACjB,eAAe,KACf,iBAAiB,KACjB,EAAM,gBAAgB,QACtB,OAAO,EAAM,eAAgB,YAC7B,UAAU,EAAM,aAKL,KACX,MAEA,EAAM,WAAW,WACjB,eAAe,KACf,kBAAkB,KAClB,WAAW,KACX,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,YAC9B,OAAO,EAAM,SAAU,UAKZ,KAAkB,MAC7B,iBAAiB,KACjB,OAAO,EAAM,eAAgB,YAC7B,EAAM,gBAAgB,QACtB,UAAU,EAAM,eAChB,aAAa,EAAM,aAKR,KACX,MAEA,EAAe,CAAK,KAAK,EAAM,YAAY,SAAS,QAKzC,KAAiB,MAC5B,EAAM,WAAW,WACjB,YAAY,KACZ,EAAM,WAAW,QACjB,OAAO,EAAM,UAAW,YACxB,UAAU,EAAM,UAChB,eAAe,KACf,kBAAkB,KAClB,OAAO,EAAM,aAAc,YAC3B,OAAO,EAAM,gBAAiB,UAKnB,KACX,MAEA,EAAc,CAAK,MAClB,EAAM,OAAO,SAAS,uBACrB,EAAM,OAAO,SAAS,mBAKb,KACX,MAEA,EAAmB,CAAK,MACvB,EAAM,YAAY,SAAS,4BAC1B,EAAM,YAAY,SAAS,wBAKlB,KACX,MAEA,EAAmB,CAAK,KACxB,EAAM,YAAY,SAAS,iCAKhB,KACX,MAEA,EAAmB,CAAK,KAAK,EAAM,YAAY,SAAS,sBAK7C,KACX,MAEA,EAAmB,CAAK,KACxB,EAAM,YAAY,SAAS,wBAKhB,KACX,MAEA,EAAc,CAAK,KAAK,EAAM,OAAO,SAAS,yBAQnC,KACX,MAEA,EAAc,CAAK,MAClB,EAAM,cAAA,eACL,EAAM,cAAA,sBAQG,KACX,MAEA,EAAc,CAAK,KACnB,EAAM,cAAA,6BAKK,KACX,MAEA,EAAM,WAAW,WACjB,mBAAmB,KACnB,WAAW,KACX,OAAO,EAAM,iBAAkB,YAC/B,MAAM,QAAQ,EAAM,KAAK,GAKd,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,gCAEvB,KACX,MACmD,EAAM,QAAQ,cAEtD,KACX,MAEA,EAAM,QAAQ,oBAEH,KACX,MAC+C,EAAM,QAAQ,SAElD,KACX,MAC8C,EAAM,QAAQ,QAKjD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,0BAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAMvB,KAA2B,MACtC,EAAyB,CAAK,KAAK,EAAmB,CAAK,GAKhD,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,sBAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,oBAEvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS,uBAKvB,KACX,MAEA,UAAU,KAAS,EAAM,SAAS;AAUpC,SAAgB,EAAmB,GAAyC;CAC1E,OAAO,EAAY,CAAK;AAC1B"}
@@ -1,2 +1,2 @@
1
- require("../_virtual/_rolldown/runtime.cjs");let e=require("react");var t={CONVERSATION_STATE:`conversation-state`,PENDING_TASK_DRAFT:`pending-task-draft`},n=`conversation-state-updated`,r={selectedTab:`files`,unpinnedTabs:[],conversationMode:`code`,subConversationTaskId:null,draftMessage:null,filesTabDiffView:null,filesTabContentViewMode:`rich`},i=new Set([`files`,`browser`,`terminal`,`planner`,`tasklist`]),a=new Set([`editor`,`served`,`changes`,`app`,`vscode`]),o=new Set([`rich`,`plain`]);function s(e){let{rightPanelShown:t,...n}=e,r=n;if(r.selectedTab!=null&&(a.has(r.selectedTab)||!i.has(r.selectedTab))&&(r={...r},delete r.selectedTab),r.unpinnedTabs){let e=r.unpinnedTabs.filter(e=>!a.has(e));e.length!==r.unpinnedTabs.length&&(r={...r,unpinnedTabs:e})}return r.filesTabContentViewMode!=null&&!o.has(r.filesTabContentViewMode)&&(r={...r},delete r.filesTabContentViewMode),r}function c(e){return e.startsWith(`task-`)}function l(e){return e===``||c(e)}function u(e){if(l(e))return r;try{let n=`${t.CONVERSATION_STATE}-${e}`,i=localStorage.getItem(n);return i===null?r:{...r,...s(JSON.parse(i))}}catch{return r}}function d(e,r){if(!l(e))try{let i=`${t.CONVERSATION_STATE}-${e}`,a={...u(e),...r};localStorage.setItem(i,JSON.stringify(a)),typeof window<`u`&&window.dispatchEvent(new CustomEvent(n,{detail:{conversationId:e}}))}catch(e){console.warn(`Failed to set conversation localStorage`,e)}}function f(e){return`${t.PENDING_TASK_DRAFT}-${e}`}function p(e){if(!e)return null;try{let t=f(e),n=localStorage.getItem(t);return localStorage.removeItem(t),n}catch(e){return console.warn(`Failed to consume pending task draft`,e),null}}function m(e){try{let r=`${t.CONVERSATION_STATE}-${e}`;localStorage.removeItem(r),typeof window<`u`&&window.dispatchEvent(new CustomEvent(n,{detail:{conversationId:e}}))}catch(t){console.warn(`Failed to clear conversation localStorage`,e,t)}}function h(r){let[i,a]=(0,e.useState)(()=>u(r));(0,e.useEffect)(()=>{if(typeof window>`u`)return;let e=`${t.CONVERSATION_STATE}-${r}`,i=()=>{a(u(r))},o=t=>{t.key===e&&i()},s=e=>{e.detail?.conversationId===r&&i()};return i(),window.addEventListener(`storage`,o),window.addEventListener(n,s),()=>{window.removeEventListener(`storage`,o),window.removeEventListener(n,s)}},[r]);let o=e=>{if(l(r)){a(t=>({...t,...e}));return}d(r,e)};return{state:i,setSelectedTab:e=>o({selectedTab:e}),setUnpinnedTabs:e=>o({unpinnedTabs:e}),setConversationMode:e=>o({conversationMode:e}),setDraftMessage:e=>o({draftMessage:e}),setFilesTabDiffView:e=>o({filesTabDiffView:e}),setFilesTabContentViewMode:e=>o({filesTabContentViewMode:e})}}exports.clearConversationLocalStorage=m,exports.consumePendingTaskDraft=p,exports.getConversationState=u,exports.isTaskConversationId=c,exports.setConversationState=d,exports.useConversationLocalStorageState=h;
1
+ require("../_virtual/_rolldown/runtime.cjs");let e=require("react");var t={CONVERSATION_STATE:`conversation-state`,PENDING_TASK_DRAFT:`pending-task-draft`},n=`conversation-state-updated`,r={selectedTab:`files`,unpinnedTabs:[],conversationMode:`code`,subConversationTaskId:null,draftMessage:null,filesTabDiffView:null,filesTabContentViewMode:`rich`},i=new Set([`files`,`browser`,`terminal`,`planner`,`tasklist`,`usage`]),a=new Set([`editor`,`served`,`changes`,`app`,`vscode`]),o=new Set([`rich`,`plain`]);function s(e){let{rightPanelShown:t,...n}=e,r=n;if(r.selectedTab!=null&&(a.has(r.selectedTab)||!i.has(r.selectedTab))&&(r={...r},delete r.selectedTab),r.unpinnedTabs){let e=r.unpinnedTabs.filter(e=>!a.has(e));e.length!==r.unpinnedTabs.length&&(r={...r,unpinnedTabs:e})}return r.filesTabContentViewMode!=null&&!o.has(r.filesTabContentViewMode)&&(r={...r},delete r.filesTabContentViewMode),r}function c(e){return e.startsWith(`task-`)}function l(e){return e===``||c(e)}function u(e){if(l(e))return r;try{let n=`${t.CONVERSATION_STATE}-${e}`,i=localStorage.getItem(n);return i===null?r:{...r,...s(JSON.parse(i))}}catch{return r}}function d(e,r){if(!l(e))try{let i=`${t.CONVERSATION_STATE}-${e}`,a={...u(e),...r};localStorage.setItem(i,JSON.stringify(a)),typeof window<`u`&&window.dispatchEvent(new CustomEvent(n,{detail:{conversationId:e}}))}catch(e){console.warn(`Failed to set conversation localStorage`,e)}}function f(e){return`${t.PENDING_TASK_DRAFT}-${e}`}function p(e){if(!e)return null;try{let t=f(e),n=localStorage.getItem(t);return localStorage.removeItem(t),n}catch(e){return console.warn(`Failed to consume pending task draft`,e),null}}function m(e){try{let r=`${t.CONVERSATION_STATE}-${e}`;localStorage.removeItem(r),typeof window<`u`&&window.dispatchEvent(new CustomEvent(n,{detail:{conversationId:e}}))}catch(t){console.warn(`Failed to clear conversation localStorage`,e,t)}}function h(r){let[i,a]=(0,e.useState)(()=>u(r));(0,e.useEffect)(()=>{if(typeof window>`u`)return;let e=`${t.CONVERSATION_STATE}-${r}`,i=()=>{a(u(r))},o=t=>{t.key===e&&i()},s=e=>{e.detail?.conversationId===r&&i()};return i(),window.addEventListener(`storage`,o),window.addEventListener(n,s),()=>{window.removeEventListener(`storage`,o),window.removeEventListener(n,s)}},[r]);let o=e=>{if(l(r)){a(t=>({...t,...e}));return}d(r,e)};return{state:i,setSelectedTab:e=>o({selectedTab:e}),setUnpinnedTabs:e=>o({unpinnedTabs:e}),setConversationMode:e=>o({conversationMode:e}),setDraftMessage:e=>o({draftMessage:e}),setFilesTabDiffView:e=>o({filesTabDiffView:e}),setFilesTabContentViewMode:e=>o({filesTabContentViewMode:e})}}exports.clearConversationLocalStorage=m,exports.consumePendingTaskDraft=p,exports.getConversationState=u,exports.isTaskConversationId=c,exports.setConversationState=d,exports.useConversationLocalStorageState=h;
2
2
  //# sourceMappingURL=conversation-local-storage.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-local-storage.cjs","names":[],"sources":["../../src/utils/conversation-local-storage.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type {\n ConversationTab,\n ConversationMode,\n} from \"#/stores/conversation-store\";\nimport type { ViewMode } from \"#/components/features/files-tab/view-mode\";\n\nexport const LOCAL_STORAGE_KEYS = {\n CONVERSATION_STATE: \"conversation-state\",\n PENDING_TASK_DRAFT: \"pending-task-draft\",\n} as const;\n\nconst CONVERSATION_STATE_UPDATED_EVENT = \"conversation-state-updated\";\n\ntype ConversationStateUpdatedDetail = {\n conversationId: string;\n};\n\n/**\n * Consolidated conversation state stored in a single localStorage key.\n *\n * NOTE: the right-drawer open/closed state is intentionally *not* persisted\n * here. Users expect the drawer to start closed every time the app is\n * (re)loaded and only stay open when they opened it themselves during the\n * current session. That state lives in the in-memory Zustand\n * `useConversationStore` (`isRightPanelShown` / `hasRightPanelToggled`)\n * which survives in-app navigation but resets on full reloads. Older\n * builds wrote a `rightPanelShown` field into this blob; we accept and\n * silently ignore that field on read so we don't churn old localStorage.\n */\nexport interface ConversationState {\n selectedTab: ConversationTab | null;\n unpinnedTabs: string[];\n conversationMode: ConversationMode;\n subConversationTaskId: string | null;\n draftMessage: string | null;\n /**\n * User's persisted choice for the Files tab diff-vs-files toggle.\n * `null` means \"no explicit choice yet\" — the Files tab then falls back\n * to its repo-aware default (diff inside a git repo with commits, files\n * otherwise).\n */\n filesTabDiffView: boolean | null;\n /** User's persisted choice for the Files tab Rich/Plain content toggle. */\n filesTabContentViewMode: ViewMode;\n}\n\nconst DEFAULT_CONVERSATION_STATE: ConversationState = {\n selectedTab: \"files\",\n unpinnedTabs: [],\n conversationMode: \"code\",\n subConversationTaskId: null,\n draftMessage: null,\n filesTabDiffView: null,\n filesTabContentViewMode: \"rich\",\n};\n\nconst VALID_CONVERSATION_TABS: ReadonlySet<ConversationTab> = new Set([\n \"files\",\n \"browser\",\n \"terminal\",\n \"planner\",\n \"tasklist\",\n]);\n\n// Tab keys that *used to* exist and were removed during the Files tab\n// refactor. We strip these out of any persisted state on read so that\n// returning users don't keep ghost entries (in `selectedTab` or\n// `unpinnedTabs`) forever — the UI has no way to surface them again to\n// be re-pinned or re-selected. We deliberately use an explicit denylist\n// here rather than a strict \"whitelist against VALID_CONVERSATION_TABS\"\n// filter because `unpinnedTabs` is typed `string[]` and other parts of\n// the app legitimately store arbitrary tab keys in it (sub-conversation\n// tab ids etc.).\nconst REMOVED_CONVERSATION_TABS: ReadonlySet<string> = new Set([\n \"editor\",\n \"served\",\n \"changes\",\n \"app\",\n \"vscode\",\n]);\n\nconst VALID_VIEW_MODES: ReadonlySet<ViewMode> = new Set([\"rich\", \"plain\"]);\n\nfunction sanitizeStoredState(\n stored: Record<string, unknown>,\n): Partial<ConversationState> {\n // `rightPanelShown` is no longer part of the schema (the drawer's\n // open state is session-only) but old persisted blobs still carry it.\n // We just drop it on the way in — keeping it in `result` here would\n // pollute the merged `ConversationState` shape that consumers receive.\n const { rightPanelShown: _ignoredRightPanelShown, ...rest } = stored as {\n rightPanelShown?: unknown;\n } & Record<string, unknown>;\n let result: Partial<ConversationState> = rest as Partial<ConversationState>;\n\n if (\n result.selectedTab != null &&\n (REMOVED_CONVERSATION_TABS.has(result.selectedTab) ||\n !VALID_CONVERSATION_TABS.has(result.selectedTab as ConversationTab))\n ) {\n result = { ...result };\n delete result.selectedTab;\n }\n\n if (result.unpinnedTabs) {\n const filtered = result.unpinnedTabs.filter(\n (tab) => !REMOVED_CONVERSATION_TABS.has(tab),\n );\n if (filtered.length !== result.unpinnedTabs.length) {\n result = { ...result, unpinnedTabs: filtered };\n }\n }\n\n // Drop a corrupt/manually-edited `filesTabContentViewMode` so it falls\n // back to the typed default (\"rich\") instead of leaking a junk string\n // into ViewMode-typed consumers. TypeScript can't help us here — the\n // value comes from `JSON.parse(localStorage.getItem(...))` which is\n // unknown at runtime.\n if (\n result.filesTabContentViewMode != null &&\n !VALID_VIEW_MODES.has(result.filesTabContentViewMode)\n ) {\n result = { ...result };\n delete result.filesTabContentViewMode;\n }\n\n return result;\n}\n\n/**\n * Check if a conversation ID is a temporary task ID that should not be persisted.\n * Task IDs have the format \"task-{uuid}\" and are used during V1 conversation initialization.\n */\nexport function isTaskConversationId(conversationId: string): boolean {\n return conversationId.startsWith(\"task-\");\n}\n\n/**\n * Whether persistence should be skipped for this conversation id.\n *\n * Skips:\n * - empty string ids (callers outside of a conversation route, e.g.\n * rendered inside a unit test without a NavigationProvider)\n * - \"task-...\" ids used as placeholders during V1 conversation\n * initialization\n */\nfunction shouldSkipPersistence(conversationId: string): boolean {\n return conversationId === \"\" || isTaskConversationId(conversationId);\n}\n\n/**\n * Get the full conversation state from localStorage.\n */\nexport function getConversationState(\n conversationId: string,\n): ConversationState {\n if (shouldSkipPersistence(conversationId)) {\n return DEFAULT_CONVERSATION_STATE;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const item = localStorage.getItem(key);\n if (item !== null) {\n return {\n ...DEFAULT_CONVERSATION_STATE,\n ...sanitizeStoredState(JSON.parse(item)),\n };\n }\n return DEFAULT_CONVERSATION_STATE;\n } catch {\n return DEFAULT_CONVERSATION_STATE;\n }\n}\n\n/**\n * Set the conversation state in localStorage, merging with existing state.\n */\nexport function setConversationState(\n conversationId: string,\n updates: Partial<ConversationState>,\n): void {\n if (shouldSkipPersistence(conversationId)) {\n return;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const currentState = getConversationState(conversationId);\n const newState = { ...currentState, ...updates };\n localStorage.setItem(key, JSON.stringify(newState));\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\"Failed to set conversation localStorage\", err);\n }\n}\n\nfunction getPendingTaskDraftKey(taskId: string): string {\n return `${LOCAL_STORAGE_KEYS.PENDING_TASK_DRAFT}-${taskId}`;\n}\n\nexport function setPendingTaskDraft(\n taskId: string | null | undefined,\n draftMessage: string,\n): void {\n if (!taskId) return;\n try {\n localStorage.setItem(getPendingTaskDraftKey(taskId), draftMessage);\n } catch (err) {\n console.warn(\"Failed to store pending task draft\", err);\n }\n}\n\nexport function consumePendingTaskDraft(\n taskId: string | null | undefined,\n): string | null {\n if (!taskId) return null;\n try {\n const key = getPendingTaskDraftKey(taskId);\n const draft = localStorage.getItem(key);\n localStorage.removeItem(key);\n return draft;\n } catch (err) {\n console.warn(\"Failed to consume pending task draft\", err);\n return null;\n }\n}\n\nexport function clearConversationLocalStorage(conversationId: string) {\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n localStorage.removeItem(key);\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\n \"Failed to clear conversation localStorage\",\n conversationId,\n err,\n );\n }\n}\n\n/**\n * React hook for conversation-scoped localStorage state.\n * Returns the full state and individual setters for each property.\n *\n * The right-drawer open state is deliberately not represented here —\n * see the note on `ConversationState` for the rationale.\n */\nexport function useConversationLocalStorageState(conversationId: string): {\n state: ConversationState;\n setSelectedTab: (tab: ConversationTab | null) => void;\n setUnpinnedTabs: (tabs: string[]) => void;\n setConversationMode: (mode: ConversationMode) => void;\n setDraftMessage: (message: string | null) => void;\n setFilesTabDiffView: (diffView: boolean | null) => void;\n setFilesTabContentViewMode: (mode: ViewMode) => void;\n} {\n const [state, setState] = useState<ConversationState>(() =>\n getConversationState(conversationId),\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n\n const syncState = () => {\n setState(getConversationState(conversationId));\n };\n\n const handleStorage = (event: StorageEvent) => {\n if (event.key === key) {\n syncState();\n }\n };\n\n const handleConversationStateUpdated = (event: Event) => {\n const customEvent = event as CustomEvent<ConversationStateUpdatedDetail>;\n if (customEvent.detail?.conversationId === conversationId) {\n syncState();\n }\n };\n\n // Ensure this hook reflects latest state for the current conversation ID.\n syncState();\n\n window.addEventListener(\"storage\", handleStorage);\n window.addEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n\n return () => {\n window.removeEventListener(\"storage\", handleStorage);\n window.removeEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n };\n }, [conversationId]);\n\n const updateState = (updates: Partial<ConversationState>) => {\n if (shouldSkipPersistence(conversationId)) {\n // No durable storage for this id (empty / task placeholder), but the\n // hook is still useful as ephemeral in-memory state — update the\n // local React mirror directly so toggles in the UI behave normally\n // until a real conversation id arrives.\n setState((prev) => ({ ...prev, ...updates }));\n return;\n }\n setConversationState(conversationId, updates);\n };\n\n return {\n state,\n setSelectedTab: (tab) => updateState({ selectedTab: tab }),\n setUnpinnedTabs: (tabs) => updateState({ unpinnedTabs: tabs }),\n setConversationMode: (mode) => updateState({ conversationMode: mode }),\n setDraftMessage: (message) => updateState({ draftMessage: message }),\n setFilesTabDiffView: (diffView) =>\n updateState({ filesTabDiffView: diffView }),\n setFilesTabContentViewMode: (mode) =>\n updateState({ filesTabContentViewMode: mode }),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conversation-local-storage.cjs","names":[],"sources":["../../src/utils/conversation-local-storage.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type {\n ConversationTab,\n ConversationMode,\n} from \"#/stores/conversation-store\";\nimport type { ViewMode } from \"#/components/features/files-tab/view-mode\";\n\nexport const LOCAL_STORAGE_KEYS = {\n CONVERSATION_STATE: \"conversation-state\",\n PENDING_TASK_DRAFT: \"pending-task-draft\",\n} as const;\n\nconst CONVERSATION_STATE_UPDATED_EVENT = \"conversation-state-updated\";\n\ntype ConversationStateUpdatedDetail = {\n conversationId: string;\n};\n\n/**\n * Consolidated conversation state stored in a single localStorage key.\n *\n * NOTE: the right-drawer open/closed state is intentionally *not* persisted\n * here. Users expect the drawer to start closed every time the app is\n * (re)loaded and only stay open when they opened it themselves during the\n * current session. That state lives in the in-memory Zustand\n * `useConversationStore` (`isRightPanelShown` / `hasRightPanelToggled`)\n * which survives in-app navigation but resets on full reloads. Older\n * builds wrote a `rightPanelShown` field into this blob; we accept and\n * silently ignore that field on read so we don't churn old localStorage.\n */\nexport interface ConversationState {\n selectedTab: ConversationTab | null;\n unpinnedTabs: string[];\n conversationMode: ConversationMode;\n subConversationTaskId: string | null;\n draftMessage: string | null;\n /**\n * User's persisted choice for the Files tab diff-vs-files toggle.\n * `null` means \"no explicit choice yet\" — the Files tab then falls back\n * to its repo-aware default (diff inside a git repo with commits, files\n * otherwise).\n */\n filesTabDiffView: boolean | null;\n /** User's persisted choice for the Files tab Rich/Plain content toggle. */\n filesTabContentViewMode: ViewMode;\n}\n\nconst DEFAULT_CONVERSATION_STATE: ConversationState = {\n selectedTab: \"files\",\n unpinnedTabs: [],\n conversationMode: \"code\",\n subConversationTaskId: null,\n draftMessage: null,\n filesTabDiffView: null,\n filesTabContentViewMode: \"rich\",\n};\n\nconst VALID_CONVERSATION_TABS: ReadonlySet<ConversationTab> = new Set([\n \"files\",\n \"browser\",\n \"terminal\",\n \"planner\",\n \"tasklist\",\n \"usage\",\n]);\n\n// Tab keys that *used to* exist and were removed during the Files tab\n// refactor. We strip these out of any persisted state on read so that\n// returning users don't keep ghost entries (in `selectedTab` or\n// `unpinnedTabs`) forever — the UI has no way to surface them again to\n// be re-pinned or re-selected. We deliberately use an explicit denylist\n// here rather than a strict \"whitelist against VALID_CONVERSATION_TABS\"\n// filter because `unpinnedTabs` is typed `string[]` and other parts of\n// the app legitimately store arbitrary tab keys in it (sub-conversation\n// tab ids etc.).\nconst REMOVED_CONVERSATION_TABS: ReadonlySet<string> = new Set([\n \"editor\",\n \"served\",\n \"changes\",\n \"app\",\n \"vscode\",\n]);\n\nconst VALID_VIEW_MODES: ReadonlySet<ViewMode> = new Set([\"rich\", \"plain\"]);\n\nfunction sanitizeStoredState(\n stored: Record<string, unknown>,\n): Partial<ConversationState> {\n // `rightPanelShown` is no longer part of the schema (the drawer's\n // open state is session-only) but old persisted blobs still carry it.\n // We just drop it on the way in — keeping it in `result` here would\n // pollute the merged `ConversationState` shape that consumers receive.\n const { rightPanelShown: _ignoredRightPanelShown, ...rest } = stored as {\n rightPanelShown?: unknown;\n } & Record<string, unknown>;\n let result: Partial<ConversationState> = rest as Partial<ConversationState>;\n\n if (\n result.selectedTab != null &&\n (REMOVED_CONVERSATION_TABS.has(result.selectedTab) ||\n !VALID_CONVERSATION_TABS.has(result.selectedTab as ConversationTab))\n ) {\n result = { ...result };\n delete result.selectedTab;\n }\n\n if (result.unpinnedTabs) {\n const filtered = result.unpinnedTabs.filter(\n (tab) => !REMOVED_CONVERSATION_TABS.has(tab),\n );\n if (filtered.length !== result.unpinnedTabs.length) {\n result = { ...result, unpinnedTabs: filtered };\n }\n }\n\n // Drop a corrupt/manually-edited `filesTabContentViewMode` so it falls\n // back to the typed default (\"rich\") instead of leaking a junk string\n // into ViewMode-typed consumers. TypeScript can't help us here — the\n // value comes from `JSON.parse(localStorage.getItem(...))` which is\n // unknown at runtime.\n if (\n result.filesTabContentViewMode != null &&\n !VALID_VIEW_MODES.has(result.filesTabContentViewMode)\n ) {\n result = { ...result };\n delete result.filesTabContentViewMode;\n }\n\n return result;\n}\n\n/**\n * Check if a conversation ID is a temporary task ID that should not be persisted.\n * Task IDs have the format \"task-{uuid}\" and are used during V1 conversation initialization.\n */\nexport function isTaskConversationId(conversationId: string): boolean {\n return conversationId.startsWith(\"task-\");\n}\n\n/**\n * Whether persistence should be skipped for this conversation id.\n *\n * Skips:\n * - empty string ids (callers outside of a conversation route, e.g.\n * rendered inside a unit test without a NavigationProvider)\n * - \"task-...\" ids used as placeholders during V1 conversation\n * initialization\n */\nfunction shouldSkipPersistence(conversationId: string): boolean {\n return conversationId === \"\" || isTaskConversationId(conversationId);\n}\n\n/**\n * Get the full conversation state from localStorage.\n */\nexport function getConversationState(\n conversationId: string,\n): ConversationState {\n if (shouldSkipPersistence(conversationId)) {\n return DEFAULT_CONVERSATION_STATE;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const item = localStorage.getItem(key);\n if (item !== null) {\n return {\n ...DEFAULT_CONVERSATION_STATE,\n ...sanitizeStoredState(JSON.parse(item)),\n };\n }\n return DEFAULT_CONVERSATION_STATE;\n } catch {\n return DEFAULT_CONVERSATION_STATE;\n }\n}\n\n/**\n * Set the conversation state in localStorage, merging with existing state.\n */\nexport function setConversationState(\n conversationId: string,\n updates: Partial<ConversationState>,\n): void {\n if (shouldSkipPersistence(conversationId)) {\n return;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const currentState = getConversationState(conversationId);\n const newState = { ...currentState, ...updates };\n localStorage.setItem(key, JSON.stringify(newState));\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\"Failed to set conversation localStorage\", err);\n }\n}\n\nfunction getPendingTaskDraftKey(taskId: string): string {\n return `${LOCAL_STORAGE_KEYS.PENDING_TASK_DRAFT}-${taskId}`;\n}\n\nexport function setPendingTaskDraft(\n taskId: string | null | undefined,\n draftMessage: string,\n): void {\n if (!taskId) return;\n try {\n localStorage.setItem(getPendingTaskDraftKey(taskId), draftMessage);\n } catch (err) {\n console.warn(\"Failed to store pending task draft\", err);\n }\n}\n\nexport function consumePendingTaskDraft(\n taskId: string | null | undefined,\n): string | null {\n if (!taskId) return null;\n try {\n const key = getPendingTaskDraftKey(taskId);\n const draft = localStorage.getItem(key);\n localStorage.removeItem(key);\n return draft;\n } catch (err) {\n console.warn(\"Failed to consume pending task draft\", err);\n return null;\n }\n}\n\nexport function clearConversationLocalStorage(conversationId: string) {\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n localStorage.removeItem(key);\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\n \"Failed to clear conversation localStorage\",\n conversationId,\n err,\n );\n }\n}\n\n/**\n * React hook for conversation-scoped localStorage state.\n * Returns the full state and individual setters for each property.\n *\n * The right-drawer open state is deliberately not represented here —\n * see the note on `ConversationState` for the rationale.\n */\nexport function useConversationLocalStorageState(conversationId: string): {\n state: ConversationState;\n setSelectedTab: (tab: ConversationTab | null) => void;\n setUnpinnedTabs: (tabs: string[]) => void;\n setConversationMode: (mode: ConversationMode) => void;\n setDraftMessage: (message: string | null) => void;\n setFilesTabDiffView: (diffView: boolean | null) => void;\n setFilesTabContentViewMode: (mode: ViewMode) => void;\n} {\n const [state, setState] = useState<ConversationState>(() =>\n getConversationState(conversationId),\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n\n const syncState = () => {\n setState(getConversationState(conversationId));\n };\n\n const handleStorage = (event: StorageEvent) => {\n if (event.key === key) {\n syncState();\n }\n };\n\n const handleConversationStateUpdated = (event: Event) => {\n const customEvent = event as CustomEvent<ConversationStateUpdatedDetail>;\n if (customEvent.detail?.conversationId === conversationId) {\n syncState();\n }\n };\n\n // Ensure this hook reflects latest state for the current conversation ID.\n syncState();\n\n window.addEventListener(\"storage\", handleStorage);\n window.addEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n\n return () => {\n window.removeEventListener(\"storage\", handleStorage);\n window.removeEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n };\n }, [conversationId]);\n\n const updateState = (updates: Partial<ConversationState>) => {\n if (shouldSkipPersistence(conversationId)) {\n // No durable storage for this id (empty / task placeholder), but the\n // hook is still useful as ephemeral in-memory state — update the\n // local React mirror directly so toggles in the UI behave normally\n // until a real conversation id arrives.\n setState((prev) => ({ ...prev, ...updates }));\n return;\n }\n setConversationState(conversationId, updates);\n };\n\n return {\n state,\n setSelectedTab: (tab) => updateState({ selectedTab: tab }),\n setUnpinnedTabs: (tabs) => updateState({ unpinnedTabs: tabs }),\n setConversationMode: (mode) => updateState({ conversationMode: mode }),\n setDraftMessage: (message) => updateState({ draftMessage: message }),\n setFilesTabDiffView: (diffView) =>\n updateState({ filesTabDiffView: diffView }),\n setFilesTabContentViewMode: (mode) =>\n updateState({ filesTabContentViewMode: mode }),\n };\n}\n"],"mappings":"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"}
@@ -16,7 +16,8 @@ var n = {
16
16
  "browser",
17
17
  "terminal",
18
18
  "planner",
19
- "tasklist"
19
+ "tasklist",
20
+ "usage"
20
21
  ]), o = new Set([
21
22
  "editor",
22
23
  "served",
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-local-storage.js","names":[],"sources":["../../src/utils/conversation-local-storage.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type {\n ConversationTab,\n ConversationMode,\n} from \"#/stores/conversation-store\";\nimport type { ViewMode } from \"#/components/features/files-tab/view-mode\";\n\nexport const LOCAL_STORAGE_KEYS = {\n CONVERSATION_STATE: \"conversation-state\",\n PENDING_TASK_DRAFT: \"pending-task-draft\",\n} as const;\n\nconst CONVERSATION_STATE_UPDATED_EVENT = \"conversation-state-updated\";\n\ntype ConversationStateUpdatedDetail = {\n conversationId: string;\n};\n\n/**\n * Consolidated conversation state stored in a single localStorage key.\n *\n * NOTE: the right-drawer open/closed state is intentionally *not* persisted\n * here. Users expect the drawer to start closed every time the app is\n * (re)loaded and only stay open when they opened it themselves during the\n * current session. That state lives in the in-memory Zustand\n * `useConversationStore` (`isRightPanelShown` / `hasRightPanelToggled`)\n * which survives in-app navigation but resets on full reloads. Older\n * builds wrote a `rightPanelShown` field into this blob; we accept and\n * silently ignore that field on read so we don't churn old localStorage.\n */\nexport interface ConversationState {\n selectedTab: ConversationTab | null;\n unpinnedTabs: string[];\n conversationMode: ConversationMode;\n subConversationTaskId: string | null;\n draftMessage: string | null;\n /**\n * User's persisted choice for the Files tab diff-vs-files toggle.\n * `null` means \"no explicit choice yet\" — the Files tab then falls back\n * to its repo-aware default (diff inside a git repo with commits, files\n * otherwise).\n */\n filesTabDiffView: boolean | null;\n /** User's persisted choice for the Files tab Rich/Plain content toggle. */\n filesTabContentViewMode: ViewMode;\n}\n\nconst DEFAULT_CONVERSATION_STATE: ConversationState = {\n selectedTab: \"files\",\n unpinnedTabs: [],\n conversationMode: \"code\",\n subConversationTaskId: null,\n draftMessage: null,\n filesTabDiffView: null,\n filesTabContentViewMode: \"rich\",\n};\n\nconst VALID_CONVERSATION_TABS: ReadonlySet<ConversationTab> = new Set([\n \"files\",\n \"browser\",\n \"terminal\",\n \"planner\",\n \"tasklist\",\n]);\n\n// Tab keys that *used to* exist and were removed during the Files tab\n// refactor. We strip these out of any persisted state on read so that\n// returning users don't keep ghost entries (in `selectedTab` or\n// `unpinnedTabs`) forever — the UI has no way to surface them again to\n// be re-pinned or re-selected. We deliberately use an explicit denylist\n// here rather than a strict \"whitelist against VALID_CONVERSATION_TABS\"\n// filter because `unpinnedTabs` is typed `string[]` and other parts of\n// the app legitimately store arbitrary tab keys in it (sub-conversation\n// tab ids etc.).\nconst REMOVED_CONVERSATION_TABS: ReadonlySet<string> = new Set([\n \"editor\",\n \"served\",\n \"changes\",\n \"app\",\n \"vscode\",\n]);\n\nconst VALID_VIEW_MODES: ReadonlySet<ViewMode> = new Set([\"rich\", \"plain\"]);\n\nfunction sanitizeStoredState(\n stored: Record<string, unknown>,\n): Partial<ConversationState> {\n // `rightPanelShown` is no longer part of the schema (the drawer's\n // open state is session-only) but old persisted blobs still carry it.\n // We just drop it on the way in — keeping it in `result` here would\n // pollute the merged `ConversationState` shape that consumers receive.\n const { rightPanelShown: _ignoredRightPanelShown, ...rest } = stored as {\n rightPanelShown?: unknown;\n } & Record<string, unknown>;\n let result: Partial<ConversationState> = rest as Partial<ConversationState>;\n\n if (\n result.selectedTab != null &&\n (REMOVED_CONVERSATION_TABS.has(result.selectedTab) ||\n !VALID_CONVERSATION_TABS.has(result.selectedTab as ConversationTab))\n ) {\n result = { ...result };\n delete result.selectedTab;\n }\n\n if (result.unpinnedTabs) {\n const filtered = result.unpinnedTabs.filter(\n (tab) => !REMOVED_CONVERSATION_TABS.has(tab),\n );\n if (filtered.length !== result.unpinnedTabs.length) {\n result = { ...result, unpinnedTabs: filtered };\n }\n }\n\n // Drop a corrupt/manually-edited `filesTabContentViewMode` so it falls\n // back to the typed default (\"rich\") instead of leaking a junk string\n // into ViewMode-typed consumers. TypeScript can't help us here — the\n // value comes from `JSON.parse(localStorage.getItem(...))` which is\n // unknown at runtime.\n if (\n result.filesTabContentViewMode != null &&\n !VALID_VIEW_MODES.has(result.filesTabContentViewMode)\n ) {\n result = { ...result };\n delete result.filesTabContentViewMode;\n }\n\n return result;\n}\n\n/**\n * Check if a conversation ID is a temporary task ID that should not be persisted.\n * Task IDs have the format \"task-{uuid}\" and are used during V1 conversation initialization.\n */\nexport function isTaskConversationId(conversationId: string): boolean {\n return conversationId.startsWith(\"task-\");\n}\n\n/**\n * Whether persistence should be skipped for this conversation id.\n *\n * Skips:\n * - empty string ids (callers outside of a conversation route, e.g.\n * rendered inside a unit test without a NavigationProvider)\n * - \"task-...\" ids used as placeholders during V1 conversation\n * initialization\n */\nfunction shouldSkipPersistence(conversationId: string): boolean {\n return conversationId === \"\" || isTaskConversationId(conversationId);\n}\n\n/**\n * Get the full conversation state from localStorage.\n */\nexport function getConversationState(\n conversationId: string,\n): ConversationState {\n if (shouldSkipPersistence(conversationId)) {\n return DEFAULT_CONVERSATION_STATE;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const item = localStorage.getItem(key);\n if (item !== null) {\n return {\n ...DEFAULT_CONVERSATION_STATE,\n ...sanitizeStoredState(JSON.parse(item)),\n };\n }\n return DEFAULT_CONVERSATION_STATE;\n } catch {\n return DEFAULT_CONVERSATION_STATE;\n }\n}\n\n/**\n * Set the conversation state in localStorage, merging with existing state.\n */\nexport function setConversationState(\n conversationId: string,\n updates: Partial<ConversationState>,\n): void {\n if (shouldSkipPersistence(conversationId)) {\n return;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const currentState = getConversationState(conversationId);\n const newState = { ...currentState, ...updates };\n localStorage.setItem(key, JSON.stringify(newState));\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\"Failed to set conversation localStorage\", err);\n }\n}\n\nfunction getPendingTaskDraftKey(taskId: string): string {\n return `${LOCAL_STORAGE_KEYS.PENDING_TASK_DRAFT}-${taskId}`;\n}\n\nexport function setPendingTaskDraft(\n taskId: string | null | undefined,\n draftMessage: string,\n): void {\n if (!taskId) return;\n try {\n localStorage.setItem(getPendingTaskDraftKey(taskId), draftMessage);\n } catch (err) {\n console.warn(\"Failed to store pending task draft\", err);\n }\n}\n\nexport function consumePendingTaskDraft(\n taskId: string | null | undefined,\n): string | null {\n if (!taskId) return null;\n try {\n const key = getPendingTaskDraftKey(taskId);\n const draft = localStorage.getItem(key);\n localStorage.removeItem(key);\n return draft;\n } catch (err) {\n console.warn(\"Failed to consume pending task draft\", err);\n return null;\n }\n}\n\nexport function clearConversationLocalStorage(conversationId: string) {\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n localStorage.removeItem(key);\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\n \"Failed to clear conversation localStorage\",\n conversationId,\n err,\n );\n }\n}\n\n/**\n * React hook for conversation-scoped localStorage state.\n * Returns the full state and individual setters for each property.\n *\n * The right-drawer open state is deliberately not represented here —\n * see the note on `ConversationState` for the rationale.\n */\nexport function useConversationLocalStorageState(conversationId: string): {\n state: ConversationState;\n setSelectedTab: (tab: ConversationTab | null) => void;\n setUnpinnedTabs: (tabs: string[]) => void;\n setConversationMode: (mode: ConversationMode) => void;\n setDraftMessage: (message: string | null) => void;\n setFilesTabDiffView: (diffView: boolean | null) => void;\n setFilesTabContentViewMode: (mode: ViewMode) => void;\n} {\n const [state, setState] = useState<ConversationState>(() =>\n getConversationState(conversationId),\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n\n const syncState = () => {\n setState(getConversationState(conversationId));\n };\n\n const handleStorage = (event: StorageEvent) => {\n if (event.key === key) {\n syncState();\n }\n };\n\n const handleConversationStateUpdated = (event: Event) => {\n const customEvent = event as CustomEvent<ConversationStateUpdatedDetail>;\n if (customEvent.detail?.conversationId === conversationId) {\n syncState();\n }\n };\n\n // Ensure this hook reflects latest state for the current conversation ID.\n syncState();\n\n window.addEventListener(\"storage\", handleStorage);\n window.addEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n\n return () => {\n window.removeEventListener(\"storage\", handleStorage);\n window.removeEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n };\n }, [conversationId]);\n\n const updateState = (updates: Partial<ConversationState>) => {\n if (shouldSkipPersistence(conversationId)) {\n // No durable storage for this id (empty / task placeholder), but the\n // hook is still useful as ephemeral in-memory state — update the\n // local React mirror directly so toggles in the UI behave normally\n // until a real conversation id arrives.\n setState((prev) => ({ ...prev, ...updates }));\n return;\n }\n setConversationState(conversationId, updates);\n };\n\n return {\n state,\n setSelectedTab: (tab) => updateState({ selectedTab: tab }),\n setUnpinnedTabs: (tabs) => updateState({ unpinnedTabs: tabs }),\n setConversationMode: (mode) => updateState({ conversationMode: mode }),\n setDraftMessage: (message) => updateState({ draftMessage: message }),\n setFilesTabDiffView: (diffView) =>\n updateState({ filesTabDiffView: diffView }),\n setFilesTabContentViewMode: (mode) =>\n updateState({ filesTabContentViewMode: mode }),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conversation-local-storage.js","names":[],"sources":["../../src/utils/conversation-local-storage.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type {\n ConversationTab,\n ConversationMode,\n} from \"#/stores/conversation-store\";\nimport type { ViewMode } from \"#/components/features/files-tab/view-mode\";\n\nexport const LOCAL_STORAGE_KEYS = {\n CONVERSATION_STATE: \"conversation-state\",\n PENDING_TASK_DRAFT: \"pending-task-draft\",\n} as const;\n\nconst CONVERSATION_STATE_UPDATED_EVENT = \"conversation-state-updated\";\n\ntype ConversationStateUpdatedDetail = {\n conversationId: string;\n};\n\n/**\n * Consolidated conversation state stored in a single localStorage key.\n *\n * NOTE: the right-drawer open/closed state is intentionally *not* persisted\n * here. Users expect the drawer to start closed every time the app is\n * (re)loaded and only stay open when they opened it themselves during the\n * current session. That state lives in the in-memory Zustand\n * `useConversationStore` (`isRightPanelShown` / `hasRightPanelToggled`)\n * which survives in-app navigation but resets on full reloads. Older\n * builds wrote a `rightPanelShown` field into this blob; we accept and\n * silently ignore that field on read so we don't churn old localStorage.\n */\nexport interface ConversationState {\n selectedTab: ConversationTab | null;\n unpinnedTabs: string[];\n conversationMode: ConversationMode;\n subConversationTaskId: string | null;\n draftMessage: string | null;\n /**\n * User's persisted choice for the Files tab diff-vs-files toggle.\n * `null` means \"no explicit choice yet\" — the Files tab then falls back\n * to its repo-aware default (diff inside a git repo with commits, files\n * otherwise).\n */\n filesTabDiffView: boolean | null;\n /** User's persisted choice for the Files tab Rich/Plain content toggle. */\n filesTabContentViewMode: ViewMode;\n}\n\nconst DEFAULT_CONVERSATION_STATE: ConversationState = {\n selectedTab: \"files\",\n unpinnedTabs: [],\n conversationMode: \"code\",\n subConversationTaskId: null,\n draftMessage: null,\n filesTabDiffView: null,\n filesTabContentViewMode: \"rich\",\n};\n\nconst VALID_CONVERSATION_TABS: ReadonlySet<ConversationTab> = new Set([\n \"files\",\n \"browser\",\n \"terminal\",\n \"planner\",\n \"tasklist\",\n \"usage\",\n]);\n\n// Tab keys that *used to* exist and were removed during the Files tab\n// refactor. We strip these out of any persisted state on read so that\n// returning users don't keep ghost entries (in `selectedTab` or\n// `unpinnedTabs`) forever — the UI has no way to surface them again to\n// be re-pinned or re-selected. We deliberately use an explicit denylist\n// here rather than a strict \"whitelist against VALID_CONVERSATION_TABS\"\n// filter because `unpinnedTabs` is typed `string[]` and other parts of\n// the app legitimately store arbitrary tab keys in it (sub-conversation\n// tab ids etc.).\nconst REMOVED_CONVERSATION_TABS: ReadonlySet<string> = new Set([\n \"editor\",\n \"served\",\n \"changes\",\n \"app\",\n \"vscode\",\n]);\n\nconst VALID_VIEW_MODES: ReadonlySet<ViewMode> = new Set([\"rich\", \"plain\"]);\n\nfunction sanitizeStoredState(\n stored: Record<string, unknown>,\n): Partial<ConversationState> {\n // `rightPanelShown` is no longer part of the schema (the drawer's\n // open state is session-only) but old persisted blobs still carry it.\n // We just drop it on the way in — keeping it in `result` here would\n // pollute the merged `ConversationState` shape that consumers receive.\n const { rightPanelShown: _ignoredRightPanelShown, ...rest } = stored as {\n rightPanelShown?: unknown;\n } & Record<string, unknown>;\n let result: Partial<ConversationState> = rest as Partial<ConversationState>;\n\n if (\n result.selectedTab != null &&\n (REMOVED_CONVERSATION_TABS.has(result.selectedTab) ||\n !VALID_CONVERSATION_TABS.has(result.selectedTab as ConversationTab))\n ) {\n result = { ...result };\n delete result.selectedTab;\n }\n\n if (result.unpinnedTabs) {\n const filtered = result.unpinnedTabs.filter(\n (tab) => !REMOVED_CONVERSATION_TABS.has(tab),\n );\n if (filtered.length !== result.unpinnedTabs.length) {\n result = { ...result, unpinnedTabs: filtered };\n }\n }\n\n // Drop a corrupt/manually-edited `filesTabContentViewMode` so it falls\n // back to the typed default (\"rich\") instead of leaking a junk string\n // into ViewMode-typed consumers. TypeScript can't help us here — the\n // value comes from `JSON.parse(localStorage.getItem(...))` which is\n // unknown at runtime.\n if (\n result.filesTabContentViewMode != null &&\n !VALID_VIEW_MODES.has(result.filesTabContentViewMode)\n ) {\n result = { ...result };\n delete result.filesTabContentViewMode;\n }\n\n return result;\n}\n\n/**\n * Check if a conversation ID is a temporary task ID that should not be persisted.\n * Task IDs have the format \"task-{uuid}\" and are used during V1 conversation initialization.\n */\nexport function isTaskConversationId(conversationId: string): boolean {\n return conversationId.startsWith(\"task-\");\n}\n\n/**\n * Whether persistence should be skipped for this conversation id.\n *\n * Skips:\n * - empty string ids (callers outside of a conversation route, e.g.\n * rendered inside a unit test without a NavigationProvider)\n * - \"task-...\" ids used as placeholders during V1 conversation\n * initialization\n */\nfunction shouldSkipPersistence(conversationId: string): boolean {\n return conversationId === \"\" || isTaskConversationId(conversationId);\n}\n\n/**\n * Get the full conversation state from localStorage.\n */\nexport function getConversationState(\n conversationId: string,\n): ConversationState {\n if (shouldSkipPersistence(conversationId)) {\n return DEFAULT_CONVERSATION_STATE;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const item = localStorage.getItem(key);\n if (item !== null) {\n return {\n ...DEFAULT_CONVERSATION_STATE,\n ...sanitizeStoredState(JSON.parse(item)),\n };\n }\n return DEFAULT_CONVERSATION_STATE;\n } catch {\n return DEFAULT_CONVERSATION_STATE;\n }\n}\n\n/**\n * Set the conversation state in localStorage, merging with existing state.\n */\nexport function setConversationState(\n conversationId: string,\n updates: Partial<ConversationState>,\n): void {\n if (shouldSkipPersistence(conversationId)) {\n return;\n }\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n const currentState = getConversationState(conversationId);\n const newState = { ...currentState, ...updates };\n localStorage.setItem(key, JSON.stringify(newState));\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\"Failed to set conversation localStorage\", err);\n }\n}\n\nfunction getPendingTaskDraftKey(taskId: string): string {\n return `${LOCAL_STORAGE_KEYS.PENDING_TASK_DRAFT}-${taskId}`;\n}\n\nexport function setPendingTaskDraft(\n taskId: string | null | undefined,\n draftMessage: string,\n): void {\n if (!taskId) return;\n try {\n localStorage.setItem(getPendingTaskDraftKey(taskId), draftMessage);\n } catch (err) {\n console.warn(\"Failed to store pending task draft\", err);\n }\n}\n\nexport function consumePendingTaskDraft(\n taskId: string | null | undefined,\n): string | null {\n if (!taskId) return null;\n try {\n const key = getPendingTaskDraftKey(taskId);\n const draft = localStorage.getItem(key);\n localStorage.removeItem(key);\n return draft;\n } catch (err) {\n console.warn(\"Failed to consume pending task draft\", err);\n return null;\n }\n}\n\nexport function clearConversationLocalStorage(conversationId: string) {\n try {\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n localStorage.removeItem(key);\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(\n new CustomEvent<ConversationStateUpdatedDetail>(\n CONVERSATION_STATE_UPDATED_EVENT,\n { detail: { conversationId } },\n ),\n );\n }\n } catch (err) {\n console.warn(\n \"Failed to clear conversation localStorage\",\n conversationId,\n err,\n );\n }\n}\n\n/**\n * React hook for conversation-scoped localStorage state.\n * Returns the full state and individual setters for each property.\n *\n * The right-drawer open state is deliberately not represented here —\n * see the note on `ConversationState` for the rationale.\n */\nexport function useConversationLocalStorageState(conversationId: string): {\n state: ConversationState;\n setSelectedTab: (tab: ConversationTab | null) => void;\n setUnpinnedTabs: (tabs: string[]) => void;\n setConversationMode: (mode: ConversationMode) => void;\n setDraftMessage: (message: string | null) => void;\n setFilesTabDiffView: (diffView: boolean | null) => void;\n setFilesTabContentViewMode: (mode: ViewMode) => void;\n} {\n const [state, setState] = useState<ConversationState>(() =>\n getConversationState(conversationId),\n );\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return undefined;\n }\n\n const key = `${LOCAL_STORAGE_KEYS.CONVERSATION_STATE}-${conversationId}`;\n\n const syncState = () => {\n setState(getConversationState(conversationId));\n };\n\n const handleStorage = (event: StorageEvent) => {\n if (event.key === key) {\n syncState();\n }\n };\n\n const handleConversationStateUpdated = (event: Event) => {\n const customEvent = event as CustomEvent<ConversationStateUpdatedDetail>;\n if (customEvent.detail?.conversationId === conversationId) {\n syncState();\n }\n };\n\n // Ensure this hook reflects latest state for the current conversation ID.\n syncState();\n\n window.addEventListener(\"storage\", handleStorage);\n window.addEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n\n return () => {\n window.removeEventListener(\"storage\", handleStorage);\n window.removeEventListener(\n CONVERSATION_STATE_UPDATED_EVENT,\n handleConversationStateUpdated,\n );\n };\n }, [conversationId]);\n\n const updateState = (updates: Partial<ConversationState>) => {\n if (shouldSkipPersistence(conversationId)) {\n // No durable storage for this id (empty / task placeholder), but the\n // hook is still useful as ephemeral in-memory state — update the\n // local React mirror directly so toggles in the UI behave normally\n // until a real conversation id arrives.\n setState((prev) => ({ ...prev, ...updates }));\n return;\n }\n setConversationState(conversationId, updates);\n };\n\n return {\n state,\n setSelectedTab: (tab) => updateState({ selectedTab: tab }),\n setUnpinnedTabs: (tabs) => updateState({ unpinnedTabs: tabs }),\n setConversationMode: (mode) => updateState({ conversationMode: mode }),\n setDraftMessage: (message) => updateState({ draftMessage: message }),\n setFilesTabDiffView: (diffView) =>\n updateState({ filesTabDiffView: diffView }),\n setFilesTabContentViewMode: (mode) =>\n updateState({ filesTabContentViewMode: mode }),\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- require("../_virtual/_rolldown/runtime.cjs");function e(e){return e?e.split(`/`).pop()||e:null}exports.formatNativeModelName=e;
1
+ require("../_virtual/_rolldown/runtime.cjs");var e=`Free`,t={"openhands/glm-5.2":`OpenHands GLM-5.2 (free)`,"openhands/deepseek-v4-flash":`OpenHands DeepSeek V4 Flash (free)`,"openhands/minimax-m2.7":`OpenHands MiniMax M2.7 (free)`},n=`Free OpenHands models: ${Object.keys(t).join(`, `)}. Other provider endpoints with similar model names may require separate billing.`,r=e=>!!(e&&e in t);function i(e){return e?r(e)?t[e]:e:null}function a(e){return e?r(e)?t[e]:e.split(`/`).pop()||e:null}exports.FREE_MODEL_BADGE_LABEL=e,exports.FREE_OPENHANDS_MODEL_NOTE=n,exports.formatModelNameForDisplay=i,exports.formatNativeModelName=a,exports.isFreeOpenHandsModel=r;
2
2
  //# sourceMappingURL=format-model-name.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-model-name.cjs","names":[],"sources":["../../src/utils/format-model-name.ts"],"sourcesContent":["/**\n * Format a native (OpenHands-kind) routing model string for display, stripping\n * the provider route prefix (e.g. ``\"anthropic/claude-sonnet-4-5-20250929\"`` →\n * ``\"claude-sonnet-4-5-20250929\"``, ``\"litellm_proxy/openai/gpt-4o\"`` →\n * ``\"gpt-4o\"``) so a conversation chip shows a meaningful model name rather than\n * the full routing path.\n *\n * Returns ``null`` for an empty/nullish input, and falls back to the original\n * string when stripping the prefix would leave nothing (e.g. a trailing slash)\n * — never an empty string, which would collapse the chip text.\n *\n * Display-only: unlike {@link deriveProfileNameFromModel} this does not sanitize\n * to an identifier, so it keeps the real model id intact for the chip.\n */\nexport function formatNativeModelName(\n model: string | null | undefined,\n): string | null {\n if (!model) return null;\n const lastSegment = model.split(\"/\").pop();\n return lastSegment || model;\n}\n"],"mappings":"6CAcA,SAAgB,EACd,EACe,CAGf,OAFK,EACe,EAAM,MAAM,GAAG,EAAE,IAC9B,GAAe,EAFH,IAGrB"}
1
+ {"version":3,"file":"format-model-name.cjs","names":[],"sources":["../../src/utils/format-model-name.ts"],"sourcesContent":["export const FREE_MODEL_BADGE_LABEL = \"Free\";\n\nexport const FREE_OPENHANDS_MODELS = {\n \"openhands/glm-5.2\": \"OpenHands GLM-5.2 (free)\",\n \"openhands/deepseek-v4-flash\": \"OpenHands DeepSeek V4 Flash (free)\",\n \"openhands/minimax-m2.7\": \"OpenHands MiniMax M2.7 (free)\",\n} as const;\n\nexport const FREE_OPENHANDS_MODEL_IDS = Object.keys(FREE_OPENHANDS_MODELS);\nexport const FREE_OPENHANDS_MODEL_NOTE = `Free OpenHands models: ${FREE_OPENHANDS_MODEL_IDS.join(\n \", \",\n)}. Other provider endpoints with similar model names may require separate billing.`;\n\nexport const isFreeOpenHandsModel = (\n model: string | null | undefined,\n): model is keyof typeof FREE_OPENHANDS_MODELS =>\n Boolean(model && model in FREE_OPENHANDS_MODELS);\n\nexport function formatModelNameForDisplay(\n model: string | null | undefined,\n): string | null {\n if (!model) return null;\n return isFreeOpenHandsModel(model) ? FREE_OPENHANDS_MODELS[model] : model;\n}\n\nexport function formatProviderModelNameForDisplay(\n provider: string | null | undefined,\n model: string | null | undefined,\n): string | null {\n if (!model) return null;\n const fullModel = provider ? `${provider}/${model}` : model;\n return isFreeOpenHandsModel(fullModel)\n ? FREE_OPENHANDS_MODELS[fullModel]\n : model;\n}\n\n/**\n * Format a native (OpenHands-kind) routing model string for display, stripping\n * the provider route prefix (e.g. ``\"anthropic/claude-sonnet-4-5-20250929\"`` →\n * ``\"claude-sonnet-4-5-20250929\"``, ``\"litellm_proxy/openai/gpt-4o\"`` →\n * ``\"gpt-4o\"``) so a conversation chip shows a meaningful model name rather than\n * the full routing path.\n *\n * Returns ``null`` for an empty/nullish input, and falls back to the original\n * string when stripping the prefix would leave nothing (e.g. a trailing slash)\n * — never an empty string, which would collapse the chip text.\n *\n * Display-only: unlike {@link deriveProfileNameFromModel} this does not sanitize\n * to an identifier, so it keeps the real model id intact for the chip.\n */\nexport function formatNativeModelName(\n model: string | null | undefined,\n): string | null {\n if (!model) return null;\n if (isFreeOpenHandsModel(model)) return FREE_OPENHANDS_MODELS[model];\n const lastSegment = model.split(\"/\").pop();\n return lastSegment || model;\n}\n"],"mappings":"6CAAA,IAAa,EAAyB,OAEzB,EAAwB,CACnC,oBAAqB,2BACrB,8BAA+B,qCAC/B,yBAA0B,+BAC5B,EAGa,EAA4B,0BADD,OAAO,KAAK,CACe,EAAyB,KAC1F,IACF,EAAE,mFAEW,EACX,GAEA,GAAQ,GAAS,KAAS,GAE5B,SAAgB,EACd,EACe,CAEf,OADK,EACE,EAAqB,CAAK,EAAI,EAAsB,GAAS,EADjD,IAErB,CA2BA,SAAgB,EACd,EACe,CAIf,OAHK,EACD,EAAqB,CAAK,EAAU,EAAsB,GAC1C,EAAM,MAAM,GAAG,EAAE,IAC9B,GAAe,EAHH,IAIrB"}