@vertesia/ui 0.66.0 → 0.68.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 (288) hide show
  1. package/lib/esm/core/components/Badge.js +1 -1
  2. package/lib/esm/core/components/Badge.js.map +1 -1
  3. package/lib/esm/core/components/FormItem.js +2 -2
  4. package/lib/esm/core/components/FormItem.js.map +1 -1
  5. package/lib/esm/core/components/InputList.js +2 -2
  6. package/lib/esm/core/components/InputList.js.map +1 -1
  7. package/lib/esm/core/components/shadcn/checkbox.js +1 -1
  8. package/lib/esm/core/components/shadcn/checkbox.js.map +1 -1
  9. package/lib/esm/core/components/shadcn/command.js +1 -1
  10. package/lib/esm/core/components/shadcn/command.js.map +1 -1
  11. package/lib/esm/core/components/shadcn/dialog.js +6 -6
  12. package/lib/esm/core/components/shadcn/dialog.js.map +1 -1
  13. package/lib/esm/core/components/shadcn/filters/DynamicLabel.js.map +1 -1
  14. package/lib/esm/core/components/shadcn/filters/comboBox/DateCombobox.js +129 -0
  15. package/lib/esm/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -0
  16. package/lib/esm/core/components/shadcn/filters/comboBox/SelectCombobox.js +46 -0
  17. package/lib/esm/core/components/shadcn/filters/comboBox/SelectCombobox.js.map +1 -0
  18. package/lib/esm/core/components/shadcn/filters/comboBox/StringListCombobox.js +23 -0
  19. package/lib/esm/core/components/shadcn/filters/comboBox/StringListCombobox.js.map +1 -0
  20. package/lib/esm/core/components/shadcn/filters/comboBox/TextCombobox.js +28 -0
  21. package/lib/esm/core/components/shadcn/filters/comboBox/TextCombobox.js.map +1 -0
  22. package/lib/esm/core/components/shadcn/filters/comboBox/comboBox.js +5 -0
  23. package/lib/esm/core/components/shadcn/filters/comboBox/comboBox.js.map +1 -0
  24. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js +101 -0
  25. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js.map +1 -0
  26. package/lib/esm/core/components/shadcn/filters/{stringListFilter.js → filter/StringListFilter.js} +3 -3
  27. package/lib/esm/core/components/shadcn/filters/filter/StringListFilter.js.map +1 -0
  28. package/lib/esm/core/components/shadcn/filters/{textFilter.js → filter/TextFilter.js} +4 -4
  29. package/lib/esm/core/components/shadcn/filters/filter/TextFilter.js.map +1 -0
  30. package/lib/esm/core/components/shadcn/filters/filter/dateFilter.js +161 -0
  31. package/lib/esm/core/components/shadcn/filters/filter/dateFilter.js.map +1 -0
  32. package/lib/esm/core/components/shadcn/filters/filter-styles.js +88 -0
  33. package/lib/esm/core/components/shadcn/filters/filter-styles.js.map +1 -0
  34. package/lib/esm/core/components/shadcn/filters/filterBar.js +128 -87
  35. package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
  36. package/lib/esm/core/components/shadcn/filters/filters.js +7 -6
  37. package/lib/esm/core/components/shadcn/filters/filters.js.map +1 -1
  38. package/lib/esm/core/components/shadcn/filters/index.js +1 -1
  39. package/lib/esm/core/components/shadcn/filters/index.js.map +1 -1
  40. package/lib/esm/core/components/shadcn/filters/types.js.map +1 -1
  41. package/lib/esm/core/components/toast/NotificationPanel.js +24 -18
  42. package/lib/esm/core/components/toast/NotificationPanel.js.map +1 -1
  43. package/lib/esm/features/agent/PayloadBuilder.js +47 -27
  44. package/lib/esm/features/agent/PayloadBuilder.js.map +1 -1
  45. package/lib/esm/features/agent/chat/ModernAgentConversation.js +10 -4
  46. package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
  47. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +7 -6
  48. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  49. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +13 -2
  50. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  51. package/lib/esm/features/agent/chat/ModernAgentOutput/SlidingMessages.js +2 -1
  52. package/lib/esm/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
  53. package/lib/esm/features/agent/chat/ModernAgentOutput/utils.js +10 -4
  54. package/lib/esm/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
  55. package/lib/esm/features/facets/DocumentsFacetsNav.js +133 -0
  56. package/lib/esm/features/facets/DocumentsFacetsNav.js.map +1 -0
  57. package/lib/esm/features/facets/RunsFacetsNav.js +125 -0
  58. package/lib/esm/features/facets/RunsFacetsNav.js.map +1 -0
  59. package/lib/esm/features/facets/VFacetsNav.js +4 -113
  60. package/lib/esm/features/facets/VFacetsNav.js.map +1 -1
  61. package/lib/esm/features/facets/VStringFacet.js +6 -4
  62. package/lib/esm/features/facets/VStringFacet.js.map +1 -1
  63. package/lib/esm/features/facets/VTypeFacet.js +4 -5
  64. package/lib/esm/features/facets/VTypeFacet.js.map +1 -1
  65. package/lib/esm/features/facets/VUserFacet.js +1 -1
  66. package/lib/esm/features/facets/VUserFacet.js.map +1 -1
  67. package/lib/esm/features/facets/WorkflowExecutionsFacetsNav.js +98 -0
  68. package/lib/esm/features/facets/WorkflowExecutionsFacetsNav.js.map +1 -0
  69. package/lib/esm/features/facets/index.js +3 -2
  70. package/lib/esm/features/facets/index.js.map +1 -1
  71. package/lib/esm/features/store/collections/CollectionsTable.js +1 -1
  72. package/lib/esm/features/store/collections/CollectionsTable.js.map +1 -1
  73. package/lib/esm/features/store/collections/CreateCollection.js +10 -9
  74. package/lib/esm/features/store/collections/CreateCollection.js.map +1 -1
  75. package/lib/esm/features/store/collections/EditCollectionView.js +10 -9
  76. package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
  77. package/lib/esm/features/store/collections/SelectCollection.js +1 -1
  78. package/lib/esm/features/store/collections/SelectCollection.js.map +1 -1
  79. package/lib/esm/features/store/objects/DocumentPreviewPanel.js +0 -1
  80. package/lib/esm/features/store/objects/DocumentPreviewPanel.js.map +1 -1
  81. package/lib/esm/features/store/objects/DocumentSearchResults.js +37 -2
  82. package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
  83. package/lib/esm/features/store/objects/components/ContentOverview.js +5 -6
  84. package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
  85. package/lib/esm/features/store/objects/components/SelectDocument.js +2 -2
  86. package/lib/esm/features/store/objects/components/SelectDocument.js.map +1 -1
  87. package/lib/esm/features/store/objects/components/VectorSearchWidget.js +1 -1
  88. package/lib/esm/features/store/objects/components/VectorSearchWidget.js.map +1 -1
  89. package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js +16 -4
  90. package/lib/esm/features/store/objects/selection/actions/AddToCollectionAction.js.map +1 -1
  91. package/lib/esm/features/store/objects/upload/DocumentUploadModal.js +72 -37
  92. package/lib/esm/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  93. package/lib/esm/features/store/types/ObjectSchemaEditor.js +15 -0
  94. package/lib/esm/features/store/types/ObjectSchemaEditor.js.map +1 -1
  95. package/lib/esm/features/user/UserInfo.js +8 -8
  96. package/lib/esm/features/user/UserInfo.js.map +1 -1
  97. package/lib/esm/layout/FullHeightLayout.js +2 -4
  98. package/lib/esm/layout/FullHeightLayout.js.map +1 -1
  99. package/lib/esm/router/HistoryNavigator.js +2 -2
  100. package/lib/esm/router/HistoryNavigator.js.map +1 -1
  101. package/lib/esm/shell/SplashScreen.js +19 -0
  102. package/lib/esm/shell/SplashScreen.js.map +1 -0
  103. package/lib/esm/shell/VertesiaShell.js +10 -0
  104. package/lib/esm/shell/VertesiaShell.js.map +1 -0
  105. package/lib/esm/shell/index.js +7 -0
  106. package/lib/esm/shell/index.js.map +1 -0
  107. package/lib/esm/shell/login/EnterpriseSigninButton.js +81 -0
  108. package/lib/esm/shell/login/EnterpriseSigninButton.js.map +1 -0
  109. package/lib/esm/shell/login/GitHubSignInButton.js +24 -0
  110. package/lib/esm/shell/login/GitHubSignInButton.js.map +1 -0
  111. package/lib/esm/shell/login/GoogleSignInButton.js +25 -0
  112. package/lib/esm/shell/login/GoogleSignInButton.js.map +1 -0
  113. package/lib/esm/shell/login/InviteAcceptModal.js +45 -0
  114. package/lib/esm/shell/login/InviteAcceptModal.js.map +1 -0
  115. package/lib/esm/shell/login/MicrosoftSigninButton.js +19 -0
  116. package/lib/esm/shell/login/MicrosoftSigninButton.js.map +1 -0
  117. package/lib/esm/shell/login/PreviewIcon.js +23 -0
  118. package/lib/esm/shell/login/PreviewIcon.js.map +1 -0
  119. package/lib/esm/shell/login/SignInModal.js +9 -0
  120. package/lib/esm/shell/login/SignInModal.js.map +1 -0
  121. package/lib/esm/shell/login/SigninScreen.js +64 -0
  122. package/lib/esm/shell/login/SigninScreen.js.map +1 -0
  123. package/lib/esm/shell/login/SignupForm.js +91 -0
  124. package/lib/esm/shell/login/SignupForm.js.map +1 -0
  125. package/lib/esm/shell/login/TerminalLogin.js +179 -0
  126. package/lib/esm/shell/login/TerminalLogin.js.map +1 -0
  127. package/lib/esm/shell/login/UserInfo.js +40 -0
  128. package/lib/esm/shell/login/UserInfo.js.map +1 -0
  129. package/lib/esm/shell/login/UserSessionMenu.js +31 -0
  130. package/lib/esm/shell/login/UserSessionMenu.js.map +1 -0
  131. package/lib/esm/shell/utils.js +6 -0
  132. package/lib/esm/shell/utils.js.map +1 -0
  133. package/lib/esm/widgets/SvgIcon.js +36 -0
  134. package/lib/esm/widgets/SvgIcon.js.map +1 -0
  135. package/lib/esm/widgets/index.js +7 -6
  136. package/lib/esm/widgets/index.js.map +1 -1
  137. package/lib/esm/widgets/upload/UploadSummary.js +1 -1
  138. package/lib/esm/widgets/upload/UploadSummary.js.map +1 -1
  139. package/lib/tsconfig.tsbuildinfo +1 -1
  140. package/lib/types/core/components/FormItem.d.ts +2 -1
  141. package/lib/types/core/components/shadcn/dialog.d.ts +2 -1
  142. package/lib/types/core/components/shadcn/filters/DynamicLabel.d.ts +1 -1
  143. package/lib/types/core/components/shadcn/filters/comboBox/DateCombobox.d.ts +5 -0
  144. package/lib/types/core/components/shadcn/filters/comboBox/SelectCombobox.d.ts +8 -0
  145. package/lib/types/core/components/shadcn/filters/comboBox/StringListCombobox.d.ts +5 -0
  146. package/lib/types/core/components/shadcn/filters/comboBox/TextCombobox.d.ts +5 -0
  147. package/lib/types/core/components/shadcn/filters/comboBox/comboBox.d.ts +4 -0
  148. package/lib/types/core/components/shadcn/filters/{selectFilter.d.ts → filter/SelectFilter.d.ts} +2 -2
  149. package/lib/types/core/components/shadcn/filters/{stringListFilter.d.ts → filter/StringListFilter.d.ts} +1 -1
  150. package/lib/types/core/components/shadcn/filters/{textFilter.d.ts → filter/TextFilter.d.ts} +1 -1
  151. package/lib/types/core/components/shadcn/filters/{dateFilter.d.ts → filter/dateFilter.d.ts} +1 -1
  152. package/lib/types/core/components/shadcn/filters/filter-styles.d.ts +1 -0
  153. package/lib/types/core/components/shadcn/filters/filterBar.d.ts +14 -4
  154. package/lib/types/core/components/shadcn/filters/index.d.ts +1 -1
  155. package/lib/types/core/components/shadcn/filters/types.d.ts +2 -0
  156. package/lib/types/features/agent/PayloadBuilder.d.ts +17 -8
  157. package/lib/types/features/agent/chat/ModernAgentOutput/utils.d.ts +2 -1
  158. package/lib/types/features/facets/DocumentsFacetsNav.d.ts +16 -0
  159. package/lib/types/features/facets/RunsFacetsNav.d.ts +18 -0
  160. package/lib/types/features/facets/VFacetsNav.d.ts +1 -1
  161. package/lib/types/features/facets/VStringFacet.d.ts +6 -2
  162. package/lib/types/features/facets/VTypeFacet.d.ts +3 -1
  163. package/lib/types/features/facets/WorkflowExecutionsFacetsNav.d.ts +13 -0
  164. package/lib/types/features/facets/index.d.ts +3 -2
  165. package/lib/types/shell/SplashScreen.d.ts +4 -0
  166. package/lib/types/shell/VertesiaShell.d.ts +7 -0
  167. package/lib/types/shell/index.d.ts +6 -0
  168. package/lib/types/shell/login/EnterpriseSigninButton.d.ts +5 -0
  169. package/lib/types/shell/login/GitHubSignInButton.d.ts +5 -0
  170. package/lib/types/shell/login/GoogleSignInButton.d.ts +5 -0
  171. package/lib/types/shell/login/InviteAcceptModal.d.ts +1 -0
  172. package/lib/types/shell/login/MicrosoftSigninButton.d.ts +5 -0
  173. package/lib/types/shell/login/PreviewIcon.d.ts +5 -0
  174. package/lib/types/shell/login/SignInModal.d.ts +6 -0
  175. package/lib/types/shell/login/SigninScreen.d.ts +8 -0
  176. package/lib/types/shell/login/SignupForm.d.ts +7 -0
  177. package/lib/types/shell/login/TerminalLogin.d.ts +1 -0
  178. package/lib/types/shell/login/UserInfo.d.ts +5 -0
  179. package/lib/types/shell/login/UserSessionMenu.d.ts +8 -0
  180. package/lib/types/shell/utils.d.ts +1 -0
  181. package/lib/types/widgets/SvgIcon.d.ts +6 -0
  182. package/lib/types/widgets/index.d.ts +7 -6
  183. package/lib/vertesia-ui-core.js +1 -1
  184. package/lib/vertesia-ui-core.js.map +1 -1
  185. package/lib/vertesia-ui-features.js +1 -1
  186. package/lib/vertesia-ui-features.js.map +1 -1
  187. package/lib/vertesia-ui-layout.js +1 -1
  188. package/lib/vertesia-ui-layout.js.map +1 -1
  189. package/lib/vertesia-ui-router.js +1 -1
  190. package/lib/vertesia-ui-router.js.map +1 -1
  191. package/lib/vertesia-ui-shell.js +2 -0
  192. package/lib/vertesia-ui-shell.js.map +1 -0
  193. package/lib/vertesia-ui-widgets.js +1 -1
  194. package/lib/vertesia-ui-widgets.js.map +1 -1
  195. package/package.json +14 -6
  196. package/src/core/components/Badge.tsx +12 -8
  197. package/src/core/components/FormItem.tsx +4 -3
  198. package/src/core/components/InputList.tsx +21 -17
  199. package/src/core/components/shadcn/checkbox.tsx +2 -2
  200. package/src/core/components/shadcn/command.tsx +1 -1
  201. package/src/core/components/shadcn/dialog.tsx +18 -9
  202. package/src/core/components/shadcn/filters/DynamicLabel.tsx +1 -2
  203. package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +211 -0
  204. package/src/core/components/shadcn/filters/{comboBox.tsx → comboBox/SelectCombobox.tsx} +8 -192
  205. package/src/core/components/shadcn/filters/comboBox/StringListCombobox.tsx +76 -0
  206. package/src/core/components/shadcn/filters/comboBox/TextCombobox.tsx +81 -0
  207. package/src/core/components/shadcn/filters/comboBox/comboBox.tsx +4 -0
  208. package/src/core/components/shadcn/filters/filter/SelectFilter.tsx +161 -0
  209. package/src/core/components/shadcn/filters/{stringListFilter.tsx → filter/StringListFilter.tsx} +7 -7
  210. package/src/core/components/shadcn/filters/{textFilter.tsx → filter/TextFilter.tsx} +17 -11
  211. package/src/core/components/shadcn/filters/filter/dateFilter.tsx +256 -0
  212. package/src/core/components/shadcn/filters/filter-styles.ts +87 -0
  213. package/src/core/components/shadcn/filters/filterBar.tsx +208 -152
  214. package/src/core/components/shadcn/filters/filters.tsx +7 -5
  215. package/src/core/components/shadcn/filters/index.ts +1 -1
  216. package/src/core/components/shadcn/filters/types.ts +2 -0
  217. package/src/core/components/toast/NotificationPanel.tsx +38 -22
  218. package/src/features/agent/PayloadBuilder.tsx +56 -31
  219. package/src/features/agent/chat/ModernAgentConversation.tsx +645 -639
  220. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +7 -6
  221. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +13 -2
  222. package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +2 -1
  223. package/src/features/agent/chat/ModernAgentOutput/utils.ts +12 -4
  224. package/src/features/facets/DocumentsFacetsNav.tsx +171 -0
  225. package/src/features/facets/RunsFacetsNav.tsx +166 -0
  226. package/src/features/facets/VFacetsNav.tsx +10 -126
  227. package/src/features/facets/VStringFacet.tsx +10 -4
  228. package/src/features/facets/VTypeFacet.tsx +6 -5
  229. package/src/features/facets/VUserFacet.tsx +5 -3
  230. package/src/features/facets/WorkflowExecutionsFacetsNav.tsx +132 -0
  231. package/src/features/facets/index.ts +5 -2
  232. package/src/features/store/collections/CollectionsTable.tsx +3 -2
  233. package/src/features/store/collections/CreateCollection.tsx +17 -15
  234. package/src/features/store/collections/EditCollectionView.tsx +19 -16
  235. package/src/features/store/collections/SelectCollection.tsx +1 -1
  236. package/src/features/store/objects/DocumentPreviewPanel.tsx +0 -1
  237. package/src/features/store/objects/DocumentSearchResults.tsx +80 -11
  238. package/src/features/store/objects/components/ContentOverview.tsx +7 -7
  239. package/src/features/store/objects/components/SelectDocument.tsx +2 -2
  240. package/src/features/store/objects/components/VectorSearchWidget.tsx +2 -2
  241. package/src/features/store/objects/selection/actions/AddToCollectionAction.tsx +40 -19
  242. package/src/features/store/objects/upload/DocumentUploadModal.tsx +160 -214
  243. package/src/features/store/types/ObjectSchemaEditor.tsx +15 -0
  244. package/src/features/user/UserInfo.tsx +17 -14
  245. package/src/layout/FullHeightLayout.tsx +2 -2
  246. package/src/router/HistoryNavigator.ts +2 -2
  247. package/src/shell/SplashScreen.tsx +41 -0
  248. package/src/shell/VertesiaShell.tsx +27 -0
  249. package/src/shell/index.tsx +6 -0
  250. package/src/shell/login/EnterpriseSigninButton.tsx +106 -0
  251. package/src/shell/login/GitHubSignInButton.tsx +40 -0
  252. package/src/shell/login/GoogleSignInButton.tsx +36 -0
  253. package/src/shell/login/InviteAcceptModal.tsx +78 -0
  254. package/src/shell/login/MicrosoftSigninButton.tsx +30 -0
  255. package/src/shell/login/PreviewIcon.tsx +29 -0
  256. package/src/shell/login/SignInModal.tsx +28 -0
  257. package/src/shell/login/SigninScreen.tsx +162 -0
  258. package/src/shell/login/SignupForm.tsx +178 -0
  259. package/src/shell/login/TerminalLogin.tsx +299 -0
  260. package/src/shell/login/UserInfo.tsx +76 -0
  261. package/src/shell/login/UserSessionMenu.tsx +81 -0
  262. package/src/shell/utils.tsx +7 -0
  263. package/src/widgets/SvgIcon.tsx +44 -0
  264. package/src/widgets/index.ts +7 -6
  265. package/src/widgets/upload/UploadSummary.tsx +3 -4
  266. package/lib/esm/core/components/shadcn/filters/comboBox.js +0 -101
  267. package/lib/esm/core/components/shadcn/filters/comboBox.js.map +0 -1
  268. package/lib/esm/core/components/shadcn/filters/dateFilter.js +0 -36
  269. package/lib/esm/core/components/shadcn/filters/dateFilter.js.map +0 -1
  270. package/lib/esm/core/components/shadcn/filters/selectFilter.js +0 -67
  271. package/lib/esm/core/components/shadcn/filters/selectFilter.js.map +0 -1
  272. package/lib/esm/core/components/shadcn/filters/stringListFilter.js.map +0 -1
  273. package/lib/esm/core/components/shadcn/filters/textFilter.js.map +0 -1
  274. package/lib/esm/features/facets/InteractionFacet.js +0 -39
  275. package/lib/esm/features/facets/InteractionFacet.js.map +0 -1
  276. package/lib/esm/features/facets/TypeOptions.js +0 -19
  277. package/lib/esm/features/facets/TypeOptions.js.map +0 -1
  278. package/lib/esm/features/facets/UserFacet.js +0 -33
  279. package/lib/esm/features/facets/UserFacet.js.map +0 -1
  280. package/lib/types/core/components/shadcn/filters/comboBox.d.ts +0 -22
  281. package/lib/types/features/facets/InteractionFacet.d.ts +0 -9
  282. package/lib/types/features/facets/TypeOptions.d.ts +0 -3
  283. package/lib/types/features/facets/UserFacet.d.ts +0 -11
  284. package/src/core/components/shadcn/filters/dateFilter.tsx +0 -82
  285. package/src/core/components/shadcn/filters/selectFilter.tsx +0 -110
  286. package/src/features/facets/InteractionFacet.tsx +0 -53
  287. package/src/features/facets/TypeOptions.tsx +0 -22
  288. package/src/features/facets/UserFacet.tsx +0 -61
@@ -1,708 +1,714 @@
1
1
  import { AsyncExecutionResult, VertesiaClient } from "@vertesia/client";
2
2
  import {
3
- AgentMessage,
4
- AgentMessageType,
5
- Plan,
6
- UserInputSignal
3
+ AgentMessage,
4
+ AgentMessageType,
5
+ Plan,
6
+ UserInputSignal
7
7
  } from "@vertesia/common";
8
8
  import { Button, MessageBox, Spinner, useToast } from "@vertesia/ui/core";
9
9
  import { useUserSession } from "@vertesia/ui/session";
10
10
  import {
11
- Bot,
12
- Cpu,
13
- SendIcon,
14
- XIcon
11
+ Bot,
12
+ Cpu,
13
+ SendIcon,
14
+ XIcon
15
15
  } from "lucide-react";
16
16
  import React, { useEffect, useMemo, useRef, useState } from "react";
17
17
  import {
18
- AnimatedThinkingDots,
19
- PulsatingCircle
18
+ AnimatedThinkingDots,
19
+ PulsatingCircle
20
20
  } from "./AnimatedThinkingDots";
21
21
  import AllMessagesMixed from "./ModernAgentOutput/AllMessagesMixed";
22
22
  import Header from "./ModernAgentOutput/Header";
23
23
  import MessageInput from "./ModernAgentOutput/MessageInput";
24
24
  import PlanPanel from "./ModernAgentOutput/PlanPanel";
25
25
  import {
26
- getWorkstreamId,
27
- insertMessageInTimeline,
28
- isInProgress,
26
+ getWorkstreamId,
27
+ insertMessageInTimeline,
28
+ isInProgress,
29
29
  } from "./ModernAgentOutput/utils";
30
30
  import { ThinkingMessages } from "./WaitingMessages";
31
31
 
32
32
  type StartWorkflowFn = (
33
- initialMessage?: string,
33
+ initialMessage?: string,
34
34
  ) => Promise<{ run_id: string; workflow_id: string } | undefined>;
35
35
 
36
36
  interface ModernAgentConversationProps {
37
- run?: AsyncExecutionResult | { workflow_id: string; run_id: string };
38
- title?: string;
39
- interactive?: boolean;
40
- onClose?: () => void;
41
- isModal?: boolean;
42
- initialMessage?: string;
43
- startWorkflow?: StartWorkflowFn;
44
- startButtonText?: string;
45
- placeholder?: string;
46
- hideUserInput?: boolean;
47
- resetWorkflow?: () => void;
37
+ run?: AsyncExecutionResult | { workflow_id: string; run_id: string };
38
+ title?: string;
39
+ interactive?: boolean;
40
+ onClose?: () => void;
41
+ isModal?: boolean;
42
+ initialMessage?: string;
43
+ startWorkflow?: StartWorkflowFn;
44
+ startButtonText?: string;
45
+ placeholder?: string;
46
+ hideUserInput?: boolean;
47
+ resetWorkflow?: () => void;
48
48
  }
49
49
 
50
50
  export function ModernAgentConversation(
51
- props: ModernAgentConversationProps,
51
+ props: ModernAgentConversationProps,
52
52
  ) {
53
- const { run, startWorkflow } = props;
54
-
55
- if (run) {
56
- // If we have a run, convert it to AsyncExecutionResult format if needed
57
- const execRun: AsyncExecutionResult =
58
- "runId" in run
59
- ? run
60
- : {
61
- runId: run.run_id,
62
- workflowId: run.workflow_id,
63
- };
64
- return <ModernAgentConversationInner {...props} run={execRun} />;
65
- } else if (startWorkflow) {
66
- // If we have startWorkflow capability but no run yet
67
- return <StartWorkflowView {...props} />;
68
- } else {
69
- // Empty state
70
- return <EmptyState />;
71
- }
53
+ const { run, startWorkflow } = props;
54
+
55
+ if (run) {
56
+ // If we have a run, convert it to AsyncExecutionResult format if needed
57
+ const execRun: AsyncExecutionResult =
58
+ "runId" in run
59
+ ? run
60
+ : {
61
+ runId: run.run_id,
62
+ workflowId: run.workflow_id,
63
+ };
64
+ return <ModernAgentConversationInner {...props} run={execRun} />;
65
+ } else if (startWorkflow) {
66
+ // If we have startWorkflow capability but no run yet
67
+ return <StartWorkflowView {...props} />;
68
+ } else {
69
+ // Empty state
70
+ return <EmptyState />;
71
+ }
72
72
  }
73
73
 
74
74
  // Empty state when no agent is running
75
75
  function EmptyState() {
76
- return (
77
- <MessageBox
78
- status="info"
79
- icon={<Bot className="size-16 text-muted mb-4" />}
80
- >
81
- <div className="text-base font-medium text-muted">
82
- No agent currently running
83
- </div>
84
- <div className="mt-3 text-sm text-muted">
85
- Select an interaction and click Start to start an agent
86
- </div>
87
- </MessageBox>
88
- );
76
+ return (
77
+ <MessageBox
78
+ status="info"
79
+ icon={<Bot className="size-16 text-muted mb-4" />}
80
+ >
81
+ <div className="text-base font-medium text-muted">
82
+ No agent currently running
83
+ </div>
84
+ <div className="mt-3 text-sm text-muted">
85
+ Select an interaction and click Start to start an agent
86
+ </div>
87
+ </MessageBox>
88
+ );
89
89
  }
90
90
 
91
91
  // Start workflow view - allows initiating a new agent conversation
92
92
  function StartWorkflowView({
93
- initialMessage,
94
- startWorkflow,
95
- onClose,
96
- isModal = false,
97
- placeholder = "Type your message...",
98
- startButtonText = "Start Agent",
99
- title = "Start New Conversation",
93
+ initialMessage,
94
+ startWorkflow,
95
+ onClose,
96
+ isModal = false,
97
+ placeholder = "Type your message...",
98
+ startButtonText = "Start Agent",
99
+ title = "Start New Conversation",
100
100
  }: ModernAgentConversationProps) {
101
- const [inputValue, setInputValue] = useState<string>("");
102
- const [isSending, setIsSending] = useState(false);
103
- const [run, setRun] = useState<AsyncExecutionResult>();
104
- const toast = useToast();
105
- const inputRef = useRef<HTMLInputElement>(null);
106
-
107
- useEffect(() => {
108
- // Focus the input field when component mounts
109
- if (inputRef.current) {
110
- inputRef.current.focus();
111
- }
112
- }, []);
113
-
114
- // Start a new workflow with the message
115
- const startWorkflowWithMessage = async () => {
116
- if (!startWorkflow) return;
117
-
118
- const message = inputValue.trim();
119
- if (!message || isSending) return;
120
-
121
- setIsSending(true);
122
- try {
123
- // Reset plan panel state when starting a new agent
124
- sessionStorage.removeItem("plan-panel-shown");
125
-
126
- toast({
127
- title: "Starting agent...",
128
- status: "info",
129
- duration: 3000,
130
- });
131
- const newRun = await startWorkflow(message);
132
- if (newRun) {
133
- setRun({
134
- runId: newRun.run_id,
135
- workflowId: newRun.workflow_id,
136
- });
137
- setInputValue("");
138
- toast({
139
- title: "Agent started",
140
- status: "success",
141
- duration: 3000,
142
- });
143
- }
144
- } catch (err: any) {
145
- toast({
146
- title: "Error starting workflow",
147
- status: "error",
148
- duration: 3000,
149
- description: err instanceof Error ? err.message : "Unknown error",
150
- });
151
- } finally {
152
- setIsSending(false);
153
- }
154
- };
101
+ const [inputValue, setInputValue] = useState<string>("");
102
+ const [isSending, setIsSending] = useState(false);
103
+ const [run, setRun] = useState<AsyncExecutionResult>();
104
+ const toast = useToast();
105
+ const inputRef = useRef<HTMLInputElement>(null);
106
+
107
+ useEffect(() => {
108
+ // Focus the input field when component mounts
109
+ if (inputRef.current) {
110
+ inputRef.current.focus();
111
+ }
112
+ }, []);
113
+
114
+ // Start a new workflow with the message
115
+ const startWorkflowWithMessage = async () => {
116
+ if (!startWorkflow) return;
155
117
 
156
- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
157
- if (e.key === "Enter" && !e.shiftKey) {
158
- e.preventDefault();
159
- startWorkflowWithMessage();
118
+ const message = inputValue.trim();
119
+ if (!message || isSending) return;
120
+
121
+ setIsSending(true);
122
+ try {
123
+ // Reset plan panel state when starting a new agent
124
+ sessionStorage.removeItem("plan-panel-shown");
125
+
126
+ toast({
127
+ title: "Starting agent...",
128
+ status: "info",
129
+ duration: 3000,
130
+ });
131
+ const newRun = await startWorkflow(message);
132
+ if (newRun) {
133
+ setRun({
134
+ runId: newRun.run_id,
135
+ workflowId: newRun.workflow_id,
136
+ });
137
+ setInputValue("");
138
+ toast({
139
+ title: "Agent started",
140
+ status: "success",
141
+ duration: 3000,
142
+ });
143
+ }
144
+ } catch (err: any) {
145
+ toast({
146
+ title: "Error starting workflow",
147
+ status: "error",
148
+ duration: 3000,
149
+ description: err instanceof Error ? err.message : "Unknown error",
150
+ });
151
+ } finally {
152
+ setIsSending(false);
153
+ }
154
+ };
155
+
156
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
157
+ if (e.key === "Enter" && !e.shiftKey) {
158
+ e.preventDefault();
159
+ startWorkflowWithMessage();
160
+ }
161
+ };
162
+
163
+ // If a run has been started, show the conversation
164
+ if (run) {
165
+ return (
166
+ <ModernAgentConversationInner
167
+ {...{ onClose, isModal, initialMessage, placeholder }}
168
+ run={run}
169
+ title={title}
170
+ />
171
+ );
160
172
  }
161
- };
162
173
 
163
- // If a run has been started, show the conversation
164
- if (run) {
165
174
  return (
166
- <ModernAgentConversationInner
167
- {...{ onClose, isModal, initialMessage, placeholder }}
168
- run={run}
169
- title={title}
170
- />
171
- );
172
- }
173
-
174
- return (
175
- <div className="flex flex-col h-full bg-white dark:bg-gray-900 overflow-hidden border-0">
176
- {/* Header */}
177
- <div className="flex items-center justify-between py-2 px-3 border-b border-gray-100 dark:border-gray-800 bg-white dark:bg-gray-900">
178
- <div className="flex items-center space-x-2">
179
- <div className="p-1">
180
- <Cpu className="h-3.5 w-3.5 text-gray-400 dark:text-gray-500" />
181
- </div>
182
- <span className="font-medium text-sm text-gray-700 dark:text-gray-300">
183
- {title}
184
- </span>
185
- </div>
175
+ <div className="flex flex-col h-full bg-white dark:bg-gray-900 overflow-hidden border-0">
176
+ {/* Header */}
177
+ <div className="flex items-center justify-between py-2 px-3 border-b border-gray-100 dark:border-gray-800 bg-white dark:bg-gray-900">
178
+ <div className="flex items-center space-x-2">
179
+ <div className="p-1">
180
+ <Cpu className="h-3.5 w-3.5 text-gray-400 dark:text-gray-500" />
181
+ </div>
182
+ <span className="font-medium text-sm text-gray-700 dark:text-gray-300">
183
+ {title}
184
+ </span>
185
+ </div>
186
+
187
+ {/* Close button if needed */}
188
+ {onClose && !isModal && (
189
+ <Button
190
+ size="xs"
191
+ variant="ghost"
192
+ onClick={onClose}
193
+ title="Close"
194
+ className="text-slate-500 hover:text-slate-700"
195
+ >
196
+ <XIcon className="h-4 w-4" />
197
+ </Button>
198
+ )}
199
+ </div>
186
200
 
187
- {/* Close button if needed */}
188
- {onClose && !isModal && (
189
- <Button
190
- size="xs"
191
- variant="ghost"
192
- onClick={onClose}
193
- title="Close"
194
- className="text-slate-500 hover:text-slate-700"
195
- >
196
- <XIcon className="h-4 w-4" />
197
- </Button>
198
- )}
199
- </div>
200
-
201
- {/* Empty conversation area with instructions */}
202
- <div className="flex-1 overflow-y-auto px-4 py-6 bg-white dark:bg-gray-900 flex flex-col items-center justify-center">
203
- {initialMessage && (
204
- <div className="px-4 py-3 mb-4 bg-blue-50/80 dark:bg-blue-900/30 border-l-2 border-blue-400 dark:border-blue-500 text-blue-700 dark:text-blue-300 max-w-md">
205
- {initialMessage}
206
- </div>
207
- )}
208
-
209
- <div className="bg-white dark:bg-slate-800 p-4 max-w-md border-l-2 border-blue-400 dark:border-blue-500">
210
- <div className="text-base text-slate-600 dark:text-slate-300 font-medium">
211
- Enter a message to start a conversation
212
- </div>
213
- <div className="mt-3 text-sm text-slate-500 dark:text-slate-400">
214
- Type your question below and press Enter or click {startButtonText}{" "}
215
- to begin
216
- </div>
217
- </div>
218
- </div>
219
-
220
- {/* Input Area */}
221
- <div className="py-3 px-3 border-t border-gray-100 dark:border-gray-800 bg-white dark:bg-gray-900">
222
- <div className="flex items-center gap-2">
223
- <div className="flex-1">
224
- <input
225
- ref={inputRef}
226
- value={inputValue}
227
- onChange={(e) => setInputValue(e.target.value)}
228
- onKeyDown={handleKeyDown}
229
- placeholder={placeholder}
230
- disabled={isSending}
231
- className="w-full py-2 px-3 text-sm border border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-white focus:border-gray-300 dark:focus:border-gray-600 focus:ring-0 rounded-md"
232
- />
233
- </div>
234
- <Button
235
- onClick={startWorkflowWithMessage}
236
- disabled={!inputValue.trim() || isSending}
237
- className="px-3 py-2 bg-gray-800 dark:bg-gray-700 hover:bg-gray-700 dark:hover:bg-gray-600 text-white text-xs rounded-md transition-colors"
238
- >
239
- {isSending ? (
240
- <Spinner size="sm" className="mr-1.5" />
241
- ) : (
242
- <SendIcon className="h-3.5 w-3.5 mr-1.5" />
243
- )}
244
- {startButtonText}
245
- </Button>
246
- </div>
247
- <div className="text-xs text-gray-400 dark:text-gray-500 mt-2 text-center">
248
- Type a message to start the conversation
201
+ {/* Empty conversation area with instructions */}
202
+ <div className="flex-1 overflow-y-auto px-4 py-6 bg-white dark:bg-gray-900 flex flex-col items-center justify-center">
203
+ {initialMessage && (
204
+ <div className="px-4 py-3 mb-4 bg-blue-50/80 dark:bg-blue-900/30 border-l-2 border-blue-400 dark:border-blue-500 text-blue-700 dark:text-blue-300 max-w-md">
205
+ {initialMessage}
206
+ </div>
207
+ )}
208
+
209
+ <div className="bg-white dark:bg-slate-800 p-4 max-w-md border-l-2 border-blue-400 dark:border-blue-500">
210
+ <div className="text-base text-slate-600 dark:text-slate-300 font-medium">
211
+ Enter a message to start a conversation
212
+ </div>
213
+ <div className="mt-3 text-sm text-slate-500 dark:text-slate-400">
214
+ Type your question below and press Enter or click {startButtonText}{" "}
215
+ to begin
216
+ </div>
217
+ </div>
218
+ </div>
219
+
220
+ {/* Input Area */}
221
+ <div className="py-3 px-3 border-t border-gray-100 dark:border-gray-800 bg-white dark:bg-gray-900">
222
+ <div className="flex items-center gap-2">
223
+ <div className="flex-1">
224
+ <input
225
+ ref={inputRef}
226
+ value={inputValue}
227
+ onChange={(e) => setInputValue(e.target.value)}
228
+ onKeyDown={handleKeyDown}
229
+ placeholder={placeholder}
230
+ disabled={isSending}
231
+ className="w-full py-2 px-3 text-sm border border-gray-200 dark:border-gray-700 dark:bg-gray-800 dark:text-white focus:border-gray-300 dark:focus:border-gray-600 focus:ring-0 rounded-md"
232
+ />
233
+ </div>
234
+ <Button
235
+ onClick={startWorkflowWithMessage}
236
+ disabled={!inputValue.trim() || isSending}
237
+ className="px-3 py-2 bg-gray-800 dark:bg-gray-700 hover:bg-gray-700 dark:hover:bg-gray-600 text-white text-xs rounded-md transition-colors"
238
+ >
239
+ {isSending ? (
240
+ <Spinner size="sm" className="mr-1.5" />
241
+ ) : (
242
+ <SendIcon className="h-3.5 w-3.5 mr-1.5" />
243
+ )}
244
+ {startButtonText}
245
+ </Button>
246
+ </div>
247
+ <div className="text-xs text-gray-400 dark:text-gray-500 mt-2 text-center">
248
+ Type a message to start the conversation
249
+ </div>
250
+ </div>
249
251
  </div>
250
- </div>
251
- </div>
252
- );
252
+ );
253
253
  }
254
254
 
255
255
  // Inner component that handles the agent conversation - similar to ModernAgentOutput
256
256
  function ModernAgentConversationInner({
257
- run,
258
- title,
259
- interactive = true,
260
- onClose,
261
- isModal = false,
262
- placeholder = "Type your message...",
263
- resetWorkflow,
257
+ run,
258
+ title,
259
+ interactive = true,
260
+ onClose,
261
+ isModal = false,
262
+ placeholder = "Type your message...",
263
+ resetWorkflow,
264
264
  }: ModernAgentConversationProps & { run: AsyncExecutionResult }) {
265
- const { client } = useUserSession();
266
- const bottomRef = useRef<HTMLDivElement | null>(null);
267
- const [messages, setMessages] = useState<AgentMessage[]>([]);
268
- const [isCompleted, setIsCompleted] = useState(false);
269
- const [inputValue, setInputValue] = useState<string>("");
270
- const [isSending, setIsSending] = useState(false);
271
- const [viewMode, setViewMode] = useState<"stacked" | "sliding">("sliding");
272
- //TODO _setShowPlanPanel state not used
273
- const [showPlanPanel, _setShowPlanPanel] = useState<boolean>(false);
274
- const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(false);
275
- // Keep track of multiple plans and their timestamps
276
- const [plans, setPlans] = useState<Array<{ plan: Plan; timestamp: number }>>(
277
- [],
278
- );
279
- // Track which plan is currently active in the UI
280
- const [activePlanIndex, setActivePlanIndex] = useState<number>(0);
281
- // Store workstream status for each plan separately
282
- const [workstreamStatusMap, setWorkstreamStatusMap] = useState<
283
- Map<
284
- number,
285
- Map<string, "pending" | "in_progress" | "completed" | "skipped">
286
- >
287
- >(new Map());
288
- const [thinkingMessageIndex, setThinkingMessageIndex] = useState(0);
289
- const toast = useToast();
290
- const [showInput, setShowInput] = useState(interactive);
291
- const [workflowStatus, setWorkflowStatus] = useState<string | null>(null);
292
-
293
- // Helper function to get the current active plan and its workstream status
294
- const getActivePlan = useMemo(() => {
295
- const currentPlanData = plans[activePlanIndex] || {
296
- plan: { plan: [] },
297
- timestamp: 0,
298
- };
299
- const currentWorkstreamStatus =
300
- workstreamStatusMap.get(currentPlanData.timestamp) || new Map();
301
- return {
302
- plan: currentPlanData.plan,
303
- workstreamStatus: currentWorkstreamStatus,
304
- };
305
- }, [plans, activePlanIndex, workstreamStatusMap]);
306
-
307
- // Show rotating thinking messages
308
- useEffect(() => {
309
- if (!isCompleted) {
310
- const interval = setInterval(() => {
311
- setThinkingMessageIndex(() =>
312
- Math.floor(Math.random() * (ThinkingMessages.length - 1)),
313
- );
314
- }, 4000);
315
- return () => clearInterval(interval);
316
- }
317
- }, [isCompleted]);
318
-
319
- const checkWorkflowStatus = async () => {
320
- try {
321
- const statusResult = await client.store.workflows.getRunDetails(run.runId, run.workflowId);
322
- setWorkflowStatus(statusResult.status as string);
323
- } catch (error) {
324
- console.error('Failed to check workflow status:', error);
265
+ const { client } = useUserSession();
266
+ const bottomRef = useRef<HTMLDivElement | null>(null);
267
+ const [messages, setMessages] = useState<AgentMessage[]>([]);
268
+ const [isCompleted, setIsCompleted] = useState(false);
269
+ const [inputValue, setInputValue] = useState<string>("");
270
+ const [isSending, setIsSending] = useState(false);
271
+ const [viewMode, setViewMode] = useState<"stacked" | "sliding">("sliding");
272
+ //TODO _setShowPlanPanel state not used
273
+ const [showPlanPanel, _setShowPlanPanel] = useState<boolean>(false);
274
+ const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(false);
275
+ // Keep track of multiple plans and their timestamps
276
+ const [plans, setPlans] = useState<Array<{ plan: Plan; timestamp: number }>>(
277
+ [],
278
+ );
279
+ // Track which plan is currently active in the UI
280
+ const [activePlanIndex, setActivePlanIndex] = useState<number>(0);
281
+ // Store workstream status for each plan separately
282
+ const [workstreamStatusMap, setWorkstreamStatusMap] = useState<
283
+ Map<
284
+ number,
285
+ Map<string, "pending" | "in_progress" | "completed" | "skipped">
286
+ >
287
+ >(new Map());
288
+ const [thinkingMessageIndex, setThinkingMessageIndex] = useState(0);
289
+ const toast = useToast();
290
+ const [showInput, setShowInput] = useState(interactive);
291
+ const [workflowStatus, setWorkflowStatus] = useState<string | null>(null);
292
+
293
+ // Helper function to get the current active plan and its workstream status
294
+ const getActivePlan = useMemo(() => {
295
+ const currentPlanData = plans[activePlanIndex] || {
296
+ plan: { plan: [] },
297
+ timestamp: 0,
298
+ };
299
+ const currentWorkstreamStatus =
300
+ workstreamStatusMap.get(currentPlanData.timestamp) || new Map();
301
+ return {
302
+ plan: currentPlanData.plan,
303
+ workstreamStatus: currentWorkstreamStatus,
304
+ };
305
+ }, [plans, activePlanIndex, workstreamStatusMap]);
306
+
307
+ // Show rotating thinking messages
308
+ useEffect(() => {
309
+ if (!isCompleted) {
310
+ const interval = setInterval(() => {
311
+ setThinkingMessageIndex(() =>
312
+ Math.floor(Math.random() * (ThinkingMessages.length - 1)),
313
+ );
314
+ }, 4000);
315
+ return () => clearInterval(interval);
316
+ }
317
+ }, [isCompleted]);
318
+
319
+ const checkWorkflowStatus = async () => {
320
+ try {
321
+ const statusResult = await client.store.workflows.getRunDetails(run.runId, run.workflowId);
322
+ setWorkflowStatus(statusResult.status as string);
323
+ } catch (error) {
324
+ console.error('Failed to check workflow status:', error);
325
+ }
325
326
  }
326
- }
327
-
328
- // Stream messages from the agent
329
- useEffect(() => {
330
- // Reset all state when runId changes (new agent)
331
- setMessages([]);
332
- setPlans([]);
333
- setActivePlanIndex(0);
334
- setWorkstreamStatusMap(new Map());
335
- setShowSlidingPanel(false);
336
- setWorkflowStatus(null);
337
-
338
- checkWorkflowStatus();
339
- client.store.workflows.streamMessages(run.runId, (message) => {
340
- if (message.message) {
341
- setMessages((prev_messages) => {
342
- if (!prev_messages.find((m) => m.timestamp === message.timestamp)) {
343
- insertMessageInTimeline(prev_messages, message);
344
- return [...prev_messages];
345
- } else {
346
- return prev_messages;
347
- }
327
+
328
+ // Stream messages from the agent
329
+ useEffect(() => {
330
+ // Reset all state when runId changes (new agent)
331
+ setMessages([]);
332
+ setPlans([]);
333
+ setActivePlanIndex(0);
334
+ setWorkstreamStatusMap(new Map());
335
+ setShowSlidingPanel(false);
336
+ setWorkflowStatus(null);
337
+
338
+ checkWorkflowStatus();
339
+ client.store.workflows.streamMessages(run.workflowId, run.runId, (message) => {
340
+ if (message.message) {
341
+ setMessages((prev_messages) => {
342
+ if (!prev_messages.find((m) => m.timestamp === message.timestamp)) {
343
+ insertMessageInTimeline(prev_messages, message);
344
+ return [...prev_messages];
345
+ } else {
346
+ return prev_messages;
347
+ }
348
+ });
349
+ }
348
350
  });
349
- }
350
- });
351
351
 
352
- // Clear messages and unsubscribe when component unmounts or runId changes
353
- return () => {
354
- setMessages([]);
355
- // Client handles unsubscribing from the message stream internally
356
- };
357
- }, [run.runId, client.store.workflows]);
358
-
359
- // Update completion status when messages change
360
- // This now accounts for multiple workstreams
361
- useEffect(() => {
362
- setIsCompleted(!isInProgress(messages));
363
-
364
- // Only automatically hide the panel when there are no plans
365
- // But don't auto-show it when plans appear
366
- if (plans.length === 0) {
367
- // If there are no plans, make sure the plan panel is hidden
368
- setShowSlidingPanel(false);
369
- }
370
- // We removed the auto-show functionality to allow users to keep the panel closed if they want
371
- }, [messages, plans.length]);
372
-
373
- // Update plans and workstream status based on incoming messages
374
- useEffect(() => {
375
- // Only show the sliding panel for the very first plan and only once
376
- if (
377
- plans.length === 1 &&
378
- !showSlidingPanel &&
379
- !sessionStorage.getItem("plan-panel-shown")
380
- ) {
381
- // For first-time plan detection only, show the panel with a delay
382
- const notificationTimeout = setTimeout(() => {
383
- setShowSlidingPanel(true);
384
- // Mark that we've shown the panel once
385
- sessionStorage.setItem("plan-panel-shown", "true");
386
- }, 500); // Short delay to ensure the UI has fully rendered
387
-
388
- return () => clearTimeout(notificationTimeout);
389
- }
352
+ // Clear messages and unsubscribe when component unmounts or runId changes
353
+ return () => {
354
+ setMessages([]);
355
+ // Client handles unsubscribing from the message stream internally
356
+ };
357
+ }, [run.runId, client.store.workflows]);
358
+
359
+ // Update completion status when messages change
360
+ // This now accounts for multiple workstreams
361
+ useEffect(() => {
362
+ setIsCompleted(!isInProgress(messages));
363
+
364
+ // Only automatically hide the panel when there are no plans
365
+ // But don't auto-show it when plans appear
366
+ if (plans.length === 0) {
367
+ // If there are no plans, make sure the plan panel is hidden
368
+ setShowSlidingPanel(false);
369
+ }
370
+ // We removed the auto-show functionality to allow users to keep the panel closed if they want
371
+ }, [messages, plans.length]);
390
372
 
391
- // Process messages to extract plan information
392
- messages.forEach((message) => {
393
- if (message.type === AgentMessageType.PLAN) {
394
- try {
395
- // Log message details for debugging
396
- console.log("PLAN message received:", message.type);
373
+ // Update plans and workstream status based on incoming messages
374
+ useEffect(() => {
375
+ // Only show the sliding panel for the very first plan and only once
376
+ if (
377
+ plans.length === 1 &&
378
+ !showSlidingPanel &&
379
+ !sessionStorage.getItem("plan-panel-shown")
380
+ ) {
381
+ // For first-time plan detection only, show the panel with a delay
382
+ const notificationTimeout = setTimeout(() => {
383
+ setShowSlidingPanel(true);
384
+ // Mark that we've shown the panel once
385
+ sessionStorage.setItem("plan-panel-shown", "true");
386
+ }, 500); // Short delay to ensure the UI has fully rendered
387
+
388
+ return () => clearTimeout(notificationTimeout);
389
+ }
397
390
 
398
- let newPlanDetails: Plan | null = null;
391
+ // Process messages to extract plan information
392
+ messages.forEach((message) => {
393
+ if (message.type === AgentMessageType.PLAN) {
394
+ try {
395
+ // Log message details for debugging
396
+ console.log("PLAN message received:", message.type);
397
+
398
+ let newPlanDetails: Plan | null = null;
399
+
400
+ // Extract the plan from the message details object
401
+ if (message.details && typeof message.details === "object") {
402
+ // For a PLAN type message like the example you provided
403
+ if (message.details.plan && Array.isArray(message.details.plan)) {
404
+ console.log("Valid plan array found in message.details.plan");
405
+ newPlanDetails = { plan: message.details.plan } as Plan;
406
+ }
407
+ }
408
+
409
+ // Only proceed if we have a valid plan
410
+ if (newPlanDetails) {
411
+ const timestamp =
412
+ typeof message.timestamp === "number"
413
+ ? message.timestamp
414
+ : new Date(message.timestamp).getTime();
415
+
416
+ // Check if we already have this plan
417
+ const existingPlanIndex = plans.findIndex(
418
+ (p) => p.timestamp === timestamp,
419
+ );
420
+
421
+ if (existingPlanIndex === -1 && newPlanDetails) {
422
+ console.log("Adding new plan to plans array");
423
+ // This is a new plan - add it to our plans array
424
+ const newPlan = {
425
+ plan: newPlanDetails,
426
+ timestamp,
427
+ };
428
+
429
+ // Add new plan to the beginning of the array (newest first)
430
+ console.log("Adding plan to plans array:", newPlan);
431
+ setPlans((prev) => {
432
+ const newPlans = [newPlan, ...prev];
433
+ console.log("New plans array:", newPlans);
434
+ return newPlans;
435
+ });
436
+ // Set this as the active plan
437
+ setActivePlanIndex(0);
438
+
439
+ // Automatically show sliding plan panel when a plan is detected
440
+ console.log("Setting showSlidingPanel to true");
441
+ setShowSlidingPanel(true);
442
+
443
+ // Initialize workstreams as pending based on the plan tasks
444
+ const newWorkstreamStatus = new Map<
445
+ string,
446
+ "pending" | "in_progress" | "completed" | "skipped"
447
+ >();
448
+
449
+ // Always initialize main workstream
450
+ newWorkstreamStatus.set("main", "in_progress");
451
+
452
+ // Initialize each task in the plan with its status
453
+ if (Array.isArray(newPlanDetails.plan)) {
454
+ newPlanDetails.plan.forEach((task) => {
455
+ if (task && typeof task === "object" && task.id) {
456
+ const taskId = task.id.toString();
457
+ // Use the task's status if available, otherwise default to pending
458
+ newWorkstreamStatus.set(taskId, task.status || "pending");
459
+ }
460
+ });
461
+ }
462
+
463
+ // Update the workstream status map with the new status for this plan
464
+ setWorkstreamStatusMap((prev) => {
465
+ const newMap = new Map(prev);
466
+ newMap.set(timestamp, newWorkstreamStatus);
467
+ return newMap;
468
+ });
469
+ }
470
+ }
471
+ } catch (error) {
472
+ console.error("Failed to parse plan from message:", error);
473
+ }
474
+ }
399
475
 
400
- // Extract the plan from the message details object
401
- if (message.details && typeof message.details === "object") {
402
- // For a PLAN type message like the example you provided
403
- if (message.details.plan && Array.isArray(message.details.plan)) {
404
- console.log("Valid plan array found in message.details.plan");
405
- newPlanDetails = { plan: message.details.plan } as Plan;
476
+ // Handle UPDATE type messages with plan updates
477
+ if (message.type === AgentMessageType.UPDATE && message.details) {
478
+ // We no longer process UPDATE messages with details.updates
479
+ // Instead, we rely on the PLAN message that follows with the complete plan
480
+ if (message.details.updates && Array.isArray(message.details.updates)) {
481
+ console.log(
482
+ "Ignoring UPDATE message with details.updates - waiting for PLAN message with full plan",
483
+ );
484
+ // This is an initial update notification, but we'll wait for the PLAN message that follows
485
+ // with the complete updated plan before making any UI changes
486
+ }
406
487
  }
407
- }
408
-
409
- // Only proceed if we have a valid plan
410
- if (newPlanDetails) {
411
- const timestamp =
412
- typeof message.timestamp === "number"
413
- ? message.timestamp
414
- : new Date(message.timestamp).getTime();
415
-
416
- // Check if we already have this plan
417
- const existingPlanIndex = plans.findIndex(
418
- (p) => p.timestamp === timestamp,
419
- );
420
-
421
- if (existingPlanIndex === -1 && newPlanDetails) {
422
- console.log("Adding new plan to plans array");
423
- // This is a new plan - add it to our plans array
424
- const newPlan = {
425
- plan: newPlanDetails,
426
- timestamp,
427
- };
428
-
429
- // Add new plan to the beginning of the array (newest first)
430
- console.log("Adding plan to plans array:", newPlan);
431
- setPlans((prev) => {
432
- const newPlans = [newPlan, ...prev];
433
- console.log("New plans array:", newPlans);
434
- return newPlans;
435
- });
436
- // Set this as the active plan
437
- setActivePlanIndex(0);
438
-
439
- // Automatically show sliding plan panel when a plan is detected
440
- console.log("Setting showSlidingPanel to true");
441
- setShowSlidingPanel(true);
442
-
443
- // Initialize workstreams as pending based on the plan tasks
444
- const newWorkstreamStatus = new Map<
445
- string,
446
- "pending" | "in_progress" | "completed" | "skipped"
447
- >();
448
-
449
- // Always initialize main workstream
450
- newWorkstreamStatus.set("main", "in_progress");
451
-
452
- // Initialize each task in the plan with its status
453
- if (Array.isArray(newPlanDetails.plan)) {
454
- newPlanDetails.plan.forEach((task) => {
455
- if (task && typeof task === "object" && task.id) {
456
- const taskId = task.id.toString();
457
- // Use the task's status if available, otherwise default to pending
458
- newWorkstreamStatus.set(taskId, task.status || "pending");
459
- }
488
+ });
489
+
490
+ const lastMessage = messages[messages.length - 1];
491
+ if (lastMessage) {
492
+ if (lastMessage.type === AgentMessageType.TERMINATED) {
493
+ setShowInput(false);
494
+ setWorkflowStatus("TERMINATED");
495
+ }
496
+ else {
497
+ if (interactive) {
498
+ setShowInput(true);
499
+ } else {
500
+ setShowInput(lastMessage.type === AgentMessageType.REQUEST_INPUT);
501
+ }
502
+ }
503
+ }
504
+ }, [messages, plans, activePlanIndex]);
505
+
506
+ // Send a message to the agent
507
+ const handleSendMessage = () => {
508
+ const message = inputValue.trim();
509
+ if (!message || isSending) return;
510
+
511
+ setIsSending(true);
512
+ setInputValue("");
513
+
514
+ client.store.workflows
515
+ .sendSignal(run.workflowId, run.runId, "UserInput", {
516
+ message,
517
+ } as UserInputSignal)
518
+ .then(() => {
519
+ setIsCompleted(false);
520
+ toast({
521
+ status: "success",
522
+ title: "Message Sent",
523
+ duration: 2000,
460
524
  });
461
- }
462
-
463
- // Update the workstream status map with the new status for this plan
464
- setWorkstreamStatusMap((prev) => {
465
- const newMap = new Map(prev);
466
- newMap.set(timestamp, newWorkstreamStatus);
467
- return newMap;
468
- });
525
+ })
526
+ .catch((err) => {
527
+ toast({
528
+ status: "error",
529
+ title: "Failed to Send Message",
530
+ description: err instanceof Error ? err.message : "Unknown error",
531
+ duration: 3000,
532
+ });
533
+ })
534
+ .finally(() => {
535
+ setIsSending(false);
536
+ });
537
+ };
538
+
539
+ // Calculate number of active tasks for the status indicator
540
+ const getActiveTaskCount = (): number => {
541
+ if (!messages.length) return 0;
542
+
543
+ // Group messages by workstream
544
+ const workstreamMessages = new Map<string, AgentMessage[]>();
545
+
546
+ messages.forEach((message) => {
547
+ const workstreamId = getWorkstreamId(message);
548
+ if (workstreamId !== "main" && workstreamId !== "all") {
549
+ if (!workstreamMessages.has(workstreamId)) {
550
+ workstreamMessages.set(workstreamId, []);
551
+ }
552
+ workstreamMessages.get(workstreamId)!.push(message);
553
+ }
554
+ });
555
+
556
+ // Count workstreams that don't have completion messages
557
+ let activeCount = 0;
558
+
559
+ for (const [_, msgs] of workstreamMessages.entries()) {
560
+ if (msgs.length > 0) {
561
+ const lastMessage = msgs[msgs.length - 1];
562
+ // If the last message isn't a completion message, the workstream is active
563
+ if (
564
+ ![AgentMessageType.COMPLETE, AgentMessageType.IDLE].includes(
565
+ lastMessage.type,
566
+ )
567
+ ) {
568
+ activeCount++;
569
+ }
469
570
  }
470
- }
471
- } catch (error) {
472
- console.error("Failed to parse plan from message:", error);
473
571
  }
474
- }
475
-
476
- // Handle UPDATE type messages with plan updates
477
- if (message.type === AgentMessageType.UPDATE && message.details) {
478
- // We no longer process UPDATE messages with details.updates
479
- // Instead, we rely on the PLAN message that follows with the complete plan
480
- if (message.details.updates && Array.isArray(message.details.updates)) {
481
- console.log(
482
- "Ignoring UPDATE message with details.updates - waiting for PLAN message with full plan",
483
- );
484
- // This is an initial update notification, but we'll wait for the PLAN message that follows
485
- // with the complete updated plan before making any UI changes
572
+
573
+ return activeCount;
574
+ };
575
+
576
+ const actualTitle =
577
+ title || run.workflowId.split(":")[2] || "Agent Conversation";
578
+
579
+ // Handle downloading conversation
580
+ const downloadConversation = async () => {
581
+ try {
582
+ const url = await getConversationUrl(client, run.runId);
583
+ if (url) window.open(url, "_blank");
584
+ } catch (err) {
585
+ console.error("Failed to download conversation", err);
586
+ toast({
587
+ status: "error",
588
+ title: "Failed to download conversation",
589
+ duration: 3000,
590
+ });
486
591
  }
487
- }
488
- });
489
-
490
- const lastMessage = messages[messages.length - 1];
491
- if (lastMessage) {
492
- if (interactive) {
493
- setShowInput(true);
494
- } else {
495
- setShowInput(lastMessage.type === AgentMessageType.REQUEST_INPUT);
496
- }
497
- }
498
- }, [messages, plans, activePlanIndex]);
499
-
500
- // Send a message to the agent
501
- const handleSendMessage = () => {
502
- const message = inputValue.trim();
503
- if (!message || isSending) return;
504
-
505
- setIsSending(true);
506
- setInputValue("");
507
-
508
- client.store.workflows
509
- .sendSignal(run.workflowId, run.runId, "UserInput", {
510
- message,
511
- } as UserInputSignal)
512
- .then(() => {
513
- setIsCompleted(false);
514
- toast({
515
- status: "success",
516
- title: "Message Sent",
517
- duration: 2000,
518
- });
519
- })
520
- .catch((err) => {
592
+ };
593
+
594
+ // Handle copying run ID
595
+ const copyRunId = () => {
596
+ navigator.clipboard.writeText(run.runId);
521
597
  toast({
522
- status: "error",
523
- title: "Failed to Send Message",
524
- description: err instanceof Error ? err.message : "Unknown error",
525
- duration: 3000,
598
+ status: "success",
599
+ title: "Run ID copied",
600
+ duration: 2000,
526
601
  });
527
- })
528
- .finally(() => {
529
- setIsSending(false);
530
- });
531
- };
532
-
533
- // Calculate number of active tasks for the status indicator
534
- const getActiveTaskCount = (): number => {
535
- if (!messages.length) return 0;
536
-
537
- // Group messages by workstream
538
- const workstreamMessages = new Map<string, AgentMessage[]>();
539
-
540
- messages.forEach((message) => {
541
- const workstreamId = getWorkstreamId(message);
542
- if (workstreamId !== "main" && workstreamId !== "all") {
543
- if (!workstreamMessages.has(workstreamId)) {
544
- workstreamMessages.set(workstreamId, []);
545
- }
546
- workstreamMessages.get(workstreamId)!.push(message);
547
- }
548
- });
602
+ };
549
603
 
550
- // Count workstreams that don't have completion messages
551
- let activeCount = 0;
604
+ return (
605
+ <div
606
+ className={`flex flex-col h-full min-h-0 ${isModal ? "rounded-lg overflow-hidden" : ""}`}
607
+ >
608
+ <Header
609
+ title={actualTitle}
610
+ isCompleted={isCompleted}
611
+ onClose={onClose}
612
+ isModal={isModal}
613
+ run={run}
614
+ viewMode={viewMode}
615
+ onViewModeChange={setViewMode}
616
+ showPlanPanel={showSlidingPanel}
617
+ hasPlan={plans.length > 0}
618
+ onTogglePlanPanel={() => {
619
+ setShowSlidingPanel(!showSlidingPanel);
620
+ // When opening the plan panel, mark that we've shown it
621
+ if (!showSlidingPanel) {
622
+ sessionStorage.setItem("plan-panel-shown", "true");
623
+ }
624
+ }}
625
+ onDownload={downloadConversation}
626
+ onCopyRunId={copyRunId}
627
+ resetWorkflow={resetWorkflow}
628
+ />
552
629
 
553
- for (const [_, msgs] of workstreamMessages.entries()) {
554
- if (msgs.length > 0) {
555
- const lastMessage = msgs[msgs.length - 1];
556
- // If the last message isn't a completion message, the workstream is active
557
- if (
558
- ![AgentMessageType.COMPLETE, AgentMessageType.IDLE].includes(
559
- lastMessage.type,
560
- )
561
- ) {
562
- activeCount++;
563
- }
564
- }
565
- }
630
+ {/* Inline Plan Panel - only shown when toggle is clicked */}
631
+ {showPlanPanel && !showSlidingPanel && plans.length > 0 && (
632
+ <PlanPanel
633
+ plan={getActivePlan.plan}
634
+ workstreamStatus={getActivePlan.workstreamStatus}
635
+ isVisible={true}
636
+ />
637
+ )}
566
638
 
567
- return activeCount;
568
- };
569
-
570
- const actualTitle =
571
- title || run.workflowId.split(":")[2] || "Agent Conversation";
572
-
573
- // Handle downloading conversation
574
- const downloadConversation = async () => {
575
- try {
576
- const url = await getConversationUrl(client, run.runId);
577
- if (url) window.open(url, "_blank");
578
- } catch (err) {
579
- console.error("Failed to download conversation", err);
580
- toast({
581
- status: "error",
582
- title: "Failed to download conversation",
583
- duration: 3000,
584
- });
585
- }
586
- };
587
-
588
- // Handle copying run ID
589
- const copyRunId = () => {
590
- navigator.clipboard.writeText(run.runId);
591
- toast({
592
- status: "success",
593
- title: "Run ID copied",
594
- duration: 2000,
595
- });
596
- };
597
-
598
- return (
599
- <div
600
- className={`flex flex-col h-full min-h-0 ${isModal ? "rounded-lg overflow-hidden" : ""}`}
601
- >
602
- <Header
603
- title={actualTitle}
604
- isCompleted={isCompleted}
605
- onClose={onClose}
606
- isModal={isModal}
607
- run={run}
608
- viewMode={viewMode}
609
- onViewModeChange={setViewMode}
610
- showPlanPanel={showSlidingPanel}
611
- hasPlan={plans.length > 0}
612
- onTogglePlanPanel={() => {
613
- setShowSlidingPanel(!showSlidingPanel);
614
- // When opening the plan panel, mark that we've shown it
615
- if (!showSlidingPanel) {
616
- sessionStorage.setItem("plan-panel-shown", "true");
617
- }
618
- }}
619
- onDownload={downloadConversation}
620
- onCopyRunId={copyRunId}
621
- resetWorkflow={resetWorkflow}
622
- />
623
-
624
- {/* Inline Plan Panel - only shown when toggle is clicked */}
625
- {showPlanPanel && !showSlidingPanel && plans.length > 0 && (
626
- <PlanPanel
627
- plan={getActivePlan.plan}
628
- workstreamStatus={getActivePlan.workstreamStatus}
629
- isVisible={true}
630
- />
631
- )}
632
-
633
- {messages.length === 0 && !isCompleted ? (
634
- <div className="flex-1 flex flex-col items-center justify-center h-full text-center py-6 bg-white dark:bg-gray-900">
635
- <div className="bg-white dark:bg-slate-800 p-5 max-w-md border border-blue-200 dark:border-blue-900/50 rounded-lg shadow-sm">
636
- <div className="flex items-center space-x-3 mb-3">
637
- <PulsatingCircle size="sm" color="blue" />
638
- <div className="text-sm text-slate-600 dark:text-slate-300 font-medium">
639
- {ThinkingMessages[thinkingMessageIndex]}
640
- </div>
641
- </div>
642
- <div className="mt-4 flex justify-center">
643
- <AnimatedThinkingDots color="blue" className="mt-1" />
644
- </div>
645
- </div>
639
+ {messages.length === 0 && !isCompleted ? (
640
+ <div className="flex-1 flex flex-col items-center justify-center h-full text-center py-6 bg-white dark:bg-gray-900">
641
+ <div className="bg-white dark:bg-slate-800 p-5 max-w-md border border-blue-200 dark:border-blue-900/50 rounded-lg shadow-sm">
642
+ <div className="flex items-center space-x-3 mb-3">
643
+ <PulsatingCircle size="sm" color="blue" />
644
+ <div className="text-sm text-slate-600 dark:text-slate-300 font-medium">
645
+ {ThinkingMessages[thinkingMessageIndex]}
646
+ </div>
647
+ </div>
648
+ <div className="mt-4 flex justify-center">
649
+ <AnimatedThinkingDots color="blue" className="mt-1" />
650
+ </div>
651
+ </div>
652
+ </div>
653
+ ) : (
654
+ <AllMessagesMixed
655
+ messages={messages}
656
+ bottomRef={bottomRef as React.RefObject<HTMLDivElement>}
657
+ viewMode={viewMode}
658
+ isCompleted={isCompleted}
659
+ plan={getActivePlan.plan}
660
+ workstreamStatus={getActivePlan.workstreamStatus}
661
+ showPlanPanel={showSlidingPanel}
662
+ onTogglePlanPanel={() => {
663
+ console.log(
664
+ "Toggle plan panel called, current state:",
665
+ showSlidingPanel,
666
+ );
667
+ setShowSlidingPanel(!showSlidingPanel);
668
+ }}
669
+ plans={plans}
670
+ activePlanIndex={activePlanIndex}
671
+ onChangePlan={(index) => setActivePlanIndex(index)}
672
+ taskLabels={getActivePlan.plan.plan?.reduce((acc, task) => {
673
+ if (task.id && task.goal) {
674
+ acc.set(task.id.toString(), task.goal);
675
+ }
676
+ return acc;
677
+ }, new Map<string, string>())}
678
+ />
679
+ )}
680
+
681
+ {workflowStatus && (
682
+ workflowStatus !== "RUNNING" ? (
683
+ <MessageBox
684
+ status={workflowStatus === "COMPLETED" ? 'success' : 'done'}
685
+ icon={null}
686
+ className="flex-shrink-0 m-2"
687
+ >
688
+ This Workflow is {workflowStatus}
689
+ </MessageBox>
690
+ ) : showInput && (
691
+ <MessageInput
692
+ value={inputValue}
693
+ onChange={setInputValue}
694
+ onSend={handleSendMessage}
695
+ disabled={false}
696
+ isSending={isSending}
697
+ isCompleted={isCompleted}
698
+ activeTaskCount={getActiveTaskCount()}
699
+ placeholder={placeholder}
700
+ />
701
+ ))}
646
702
  </div>
647
- ) : (
648
- <AllMessagesMixed
649
- messages={messages}
650
- bottomRef={bottomRef as React.RefObject<HTMLDivElement>}
651
- viewMode={viewMode}
652
- isCompleted={isCompleted}
653
- plan={getActivePlan.plan}
654
- workstreamStatus={getActivePlan.workstreamStatus}
655
- showPlanPanel={showSlidingPanel}
656
- onTogglePlanPanel={() => {
657
- console.log(
658
- "Toggle plan panel called, current state:",
659
- showSlidingPanel,
660
- );
661
- setShowSlidingPanel(!showSlidingPanel);
662
- }}
663
- plans={plans}
664
- activePlanIndex={activePlanIndex}
665
- onChangePlan={(index) => setActivePlanIndex(index)}
666
- taskLabels={getActivePlan.plan.plan?.reduce((acc, task) => {
667
- if (task.id && task.goal) {
668
- acc.set(task.id.toString(), task.goal);
669
- }
670
- return acc;
671
- }, new Map<string, string>())}
672
- />
673
- )}
674
-
675
- {workflowStatus && (
676
- workflowStatus !== "RUNNING" ? (
677
- <MessageBox
678
- status={workflowStatus === "COMPLETED" ? 'success' : 'done'}
679
- icon={null}
680
- className="flex-shrink-0 m-2"
681
- >
682
- This Workflow is {workflowStatus}
683
- </MessageBox>
684
- ) : showInput && (
685
- <MessageInput
686
- value={inputValue}
687
- onChange={setInputValue}
688
- onSend={handleSendMessage}
689
- disabled={false}
690
- isSending={isSending}
691
- isCompleted={isCompleted}
692
- activeTaskCount={getActiveTaskCount()}
693
- placeholder={placeholder}
694
- />
695
- ))}
696
- </div>
697
- );
703
+ );
698
704
  }
699
705
 
700
706
  // Helper function to get conversation URL - used by other components
701
707
  export async function getConversationUrl(
702
- vertesia: VertesiaClient,
703
- workflowRunId: string,
708
+ vertesia: VertesiaClient,
709
+ workflowRunId: string,
704
710
  ): Promise<string> {
705
- return vertesia.files
706
- .getDownloadUrl(`agents/${workflowRunId}/conversation.json`)
707
- .then((r) => r.url);
711
+ return vertesia.files
712
+ .getDownloadUrl(`agents/${workflowRunId}/conversation.json`)
713
+ .then((r) => r.url);
708
714
  }