@vertesia/ui 1.4.0 → 1.5.0-dev.20260713.151751Z

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 (344) hide show
  1. package/lib/core/components/InputList.d.ts.map +1 -1
  2. package/lib/core/components/InputList.js +3 -2
  3. package/lib/core/components/InputList.js.map +1 -1
  4. package/lib/core/components/SelectList.d.ts.map +1 -1
  5. package/lib/core/components/SelectList.js +1 -1
  6. package/lib/core/components/SelectList.js.map +1 -1
  7. package/lib/core/components/TagsInput.d.ts.map +1 -1
  8. package/lib/core/components/TagsInput.js +36 -4
  9. package/lib/core/components/TagsInput.js.map +1 -1
  10. package/lib/core/components/popup/Popup.js +2 -1
  11. package/lib/core/components/popup/Popup.js.map +1 -1
  12. package/lib/core/components/popup/position.d.ts.map +1 -1
  13. package/lib/core/components/popup/position.js +3 -6
  14. package/lib/core/components/popup/position.js.map +1 -1
  15. package/lib/core/components/shadcn/badge.d.ts +2 -2
  16. package/lib/core/components/shadcn/badge.d.ts.map +1 -1
  17. package/lib/core/components/shadcn/badge.js +3 -0
  18. package/lib/core/components/shadcn/badge.js.map +1 -1
  19. package/lib/core/components/shadcn/breadcrumb.d.ts.map +1 -1
  20. package/lib/core/components/shadcn/breadcrumb.js +2 -2
  21. package/lib/core/components/shadcn/breadcrumb.js.map +1 -1
  22. package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  23. package/lib/core/components/shadcn/filters/filterBar.js +1 -3
  24. package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
  25. package/lib/core/components/shadcn/resizeable.d.ts +1 -1
  26. package/lib/core/components/shadcn/resizeable.d.ts.map +1 -1
  27. package/lib/core/components/shadcn/resizeable.js +12 -2
  28. package/lib/core/components/shadcn/resizeable.js.map +1 -1
  29. package/lib/core/components/shadcn/selectBox.d.ts +7 -1
  30. package/lib/core/components/shadcn/selectBox.d.ts.map +1 -1
  31. package/lib/core/components/shadcn/selectBox.js +29 -12
  32. package/lib/core/components/shadcn/selectBox.js.map +1 -1
  33. package/lib/core/components/table/index.d.ts.map +1 -1
  34. package/lib/core/components/table/index.js +1 -1
  35. package/lib/core/components/table/index.js.map +1 -1
  36. package/lib/core/hooks/useIntersectionObserver.d.ts.map +1 -1
  37. package/lib/core/hooks/useIntersectionObserver.js +3 -1
  38. package/lib/core/hooks/useIntersectionObserver.js.map +1 -1
  39. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  40. package/lib/features/agent/chat/AgentRightPanel.js +3 -6
  41. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  42. package/lib/features/agent/chat/AnimatedThinkingDots.d.ts.map +1 -1
  43. package/lib/features/agent/chat/AnimatedThinkingDots.js +1 -1
  44. package/lib/features/agent/chat/AnimatedThinkingDots.js.map +1 -1
  45. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  46. package/lib/features/agent/chat/AskUserWidget.js +4 -3
  47. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  48. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  49. package/lib/features/agent/chat/ModernAgentConversation.js +56 -11
  50. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  51. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +8 -1
  52. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  53. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +40 -31
  54. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  55. package/lib/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js +3 -3
  56. package/lib/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js.map +1 -1
  57. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  58. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +5 -1
  59. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  60. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -7
  61. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  62. package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.d.ts.map +1 -1
  63. package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.js +5 -5
  64. package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.js.map +1 -1
  65. package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.d.ts.map +1 -1
  66. package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js +4 -4
  67. package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js.map +1 -1
  68. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
  69. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +3 -3
  70. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
  71. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.d.ts.map +1 -1
  72. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +156 -8
  73. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
  74. package/lib/features/agent/chat/hooks/useFileProcessing.d.ts +1 -0
  75. package/lib/features/agent/chat/hooks/useFileProcessing.d.ts.map +1 -1
  76. package/lib/features/agent/chat/hooks/useFileProcessing.js +37 -3
  77. package/lib/features/agent/chat/hooks/useFileProcessing.js.map +1 -1
  78. package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
  79. package/lib/features/facets/AgentRunnerFacetsNav.js +1 -1
  80. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  81. package/lib/features/facets/InteractionsFacetsNav.d.ts +10 -1
  82. package/lib/features/facets/InteractionsFacetsNav.d.ts.map +1 -1
  83. package/lib/features/facets/InteractionsFacetsNav.js +14 -5
  84. package/lib/features/facets/InteractionsFacetsNav.js.map +1 -1
  85. package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
  86. package/lib/features/facets/PromptsFacetsNav.js +12 -1
  87. package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
  88. package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
  89. package/lib/features/facets/RunsFacetsNav.js +1 -1
  90. package/lib/features/facets/RunsFacetsNav.js.map +1 -1
  91. package/lib/features/magic-pdf/AnnotatedImageSlider.d.ts.map +1 -1
  92. package/lib/features/magic-pdf/AnnotatedImageSlider.js +1 -3
  93. package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
  94. package/lib/features/magic-pdf/MagicPdfProvider.js +2 -3
  95. package/lib/features/magic-pdf/MagicPdfProvider.js.map +1 -1
  96. package/lib/features/store/objects/DocumentSearchResults.d.ts +6 -2
  97. package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  98. package/lib/features/store/objects/DocumentSearchResults.js +6 -6
  99. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  100. package/lib/features/store/objects/components/ContentOverview.js +1 -1
  101. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  102. package/lib/features/store/objects/components/DocumentIcon.d.ts.map +1 -1
  103. package/lib/features/store/objects/components/DocumentIcon.js +1 -1
  104. package/lib/features/store/objects/components/DocumentIcon.js.map +1 -1
  105. package/lib/features/store/objects/components/DocumentInput.js.map +1 -1
  106. package/lib/features/store/objects/search/DocumentSearchContext.d.ts +4 -4
  107. package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
  108. package/lib/features/store/objects/search/DocumentSearchContext.js +1 -1
  109. package/lib/features/store/objects/search/DocumentSearchContext.js.map +1 -1
  110. package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
  111. package/lib/features/store/objects/selection/ObjectsActionContext.js +2 -25
  112. package/lib/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
  113. package/lib/features/store/objects/selection/ObjectsActionContextClass.d.ts +0 -2
  114. package/lib/features/store/objects/selection/ObjectsActionContextClass.d.ts.map +1 -1
  115. package/lib/features/store/objects/selection/ObjectsActionContextClass.js +1 -7
  116. package/lib/features/store/objects/selection/ObjectsActionContextClass.js.map +1 -1
  117. package/lib/features/store/objects/selection/ObjectsActionHooks.d.ts +0 -1
  118. package/lib/features/store/objects/selection/ObjectsActionHooks.d.ts.map +1 -1
  119. package/lib/features/store/objects/selection/ObjectsActionHooks.js +0 -10
  120. package/lib/features/store/objects/selection/ObjectsActionHooks.js.map +1 -1
  121. package/lib/features/store/objects/selection/SelectionActions.d.ts +4 -0
  122. package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
  123. package/lib/features/store/objects/selection/SelectionActions.js +4 -18
  124. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  125. package/lib/features/store/objects/selection/actions/DeleteObjectsAction.d.ts.map +1 -1
  126. package/lib/features/store/objects/selection/actions/DeleteObjectsAction.js +16 -7
  127. package/lib/features/store/objects/selection/actions/DeleteObjectsAction.js.map +1 -1
  128. package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts +7 -0
  129. package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts.map +1 -0
  130. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +51 -0
  131. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +1 -0
  132. package/lib/features/store/objects/selection/actions/index.d.ts +0 -1
  133. package/lib/features/store/objects/selection/actions/index.d.ts.map +1 -1
  134. package/lib/features/store/objects/selection/actions/index.js +0 -1
  135. package/lib/features/store/objects/selection/actions/index.js.map +1 -1
  136. package/lib/features/store/types/ContentObjectTypesSearch.d.ts.map +1 -1
  137. package/lib/features/store/types/ContentObjectTypesSearch.js +55 -3
  138. package/lib/features/store/types/ContentObjectTypesSearch.js.map +1 -1
  139. package/lib/features/store/types/ContentObjectTypesTable.d.ts +5 -1
  140. package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
  141. package/lib/features/store/types/ContentObjectTypesTable.js +4 -2
  142. package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
  143. package/lib/features/store/types/search/ObjectTypeSearchContext.js +1 -1
  144. package/lib/features/store/types/search/ObjectTypeSearchContext.js.map +1 -1
  145. package/lib/i18n/locales/ar.json +17 -0
  146. package/lib/i18n/locales/de.json +17 -0
  147. package/lib/i18n/locales/en.json +33 -0
  148. package/lib/i18n/locales/es.json +17 -0
  149. package/lib/i18n/locales/fr.json +17 -0
  150. package/lib/i18n/locales/it.json +17 -0
  151. package/lib/i18n/locales/ja.json +17 -0
  152. package/lib/i18n/locales/ko.json +17 -0
  153. package/lib/i18n/locales/pt.json +17 -0
  154. package/lib/i18n/locales/ru.json +17 -0
  155. package/lib/i18n/locales/tr.json +17 -0
  156. package/lib/i18n/locales/zh-TW.json +17 -0
  157. package/lib/i18n/locales/zh.json +17 -0
  158. package/lib/layout/Sidebar.d.ts +5 -1
  159. package/lib/layout/Sidebar.d.ts.map +1 -1
  160. package/lib/layout/Sidebar.js.map +1 -1
  161. package/lib/router/NestedRouterProvider.d.ts +1 -1
  162. package/lib/router/NestedRouterProvider.d.ts.map +1 -1
  163. package/lib/router/NestedRouterProvider.js +2 -2
  164. package/lib/router/NestedRouterProvider.js.map +1 -1
  165. package/lib/router/Redirect.d.ts +13 -0
  166. package/lib/router/Redirect.d.ts.map +1 -0
  167. package/lib/router/Redirect.js +20 -0
  168. package/lib/router/Redirect.js.map +1 -0
  169. package/lib/router/Router.d.ts.map +1 -1
  170. package/lib/router/Router.js +1 -2
  171. package/lib/router/Router.js.map +1 -1
  172. package/lib/router/index.d.ts +1 -0
  173. package/lib/router/index.d.ts.map +1 -1
  174. package/lib/router/index.js +1 -0
  175. package/lib/router/index.js.map +1 -1
  176. package/lib/session/DevSessionProvider.d.ts +8 -0
  177. package/lib/session/DevSessionProvider.d.ts.map +1 -0
  178. package/lib/session/DevSessionProvider.js +33 -0
  179. package/lib/session/DevSessionProvider.js.map +1 -0
  180. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  181. package/lib/session/UserSessionProvider.js +16 -2
  182. package/lib/session/UserSessionProvider.js.map +1 -1
  183. package/lib/session/auth/composable.d.ts +10 -1
  184. package/lib/session/auth/composable.d.ts.map +1 -1
  185. package/lib/session/auth/composable.js +38 -2
  186. package/lib/session/auth/composable.js.map +1 -1
  187. package/lib/session/index.d.ts +1 -0
  188. package/lib/session/index.d.ts.map +1 -1
  189. package/lib/session/index.js +1 -0
  190. package/lib/session/index.js.map +1 -1
  191. package/lib/shell/VertesiaShell.d.ts +3 -1
  192. package/lib/shell/VertesiaShell.d.ts.map +1 -1
  193. package/lib/shell/VertesiaShell.js +5 -4
  194. package/lib/shell/VertesiaShell.js.map +1 -1
  195. package/lib/shell/login/SignInRestrictedEnvStep.d.ts +14 -0
  196. package/lib/shell/login/SignInRestrictedEnvStep.d.ts.map +1 -0
  197. package/lib/shell/login/SignInRestrictedEnvStep.js +50 -0
  198. package/lib/shell/login/SignInRestrictedEnvStep.js.map +1 -0
  199. package/lib/shell/login/SigninScreen.d.ts.map +1 -1
  200. package/lib/shell/login/SigninScreen.js +16 -3
  201. package/lib/shell/login/SigninScreen.js.map +1 -1
  202. package/lib/shell/login/productionUrl.d.ts +16 -0
  203. package/lib/shell/login/productionUrl.d.ts.map +1 -0
  204. package/lib/shell/login/productionUrl.js +19 -0
  205. package/lib/shell/login/productionUrl.js.map +1 -0
  206. package/lib/shell/login/signInUtils.d.ts.map +1 -1
  207. package/lib/shell/login/signInUtils.js +14 -1
  208. package/lib/shell/login/signInUtils.js.map +1 -1
  209. package/lib/vertesia-ui-core.js +95 -2
  210. package/lib/vertesia-ui-core.js.map +1 -1
  211. package/lib/vertesia-ui-env.js +2 -2
  212. package/lib/vertesia-ui-env.js.map +1 -1
  213. package/lib/vertesia-ui-features.js +454 -2
  214. package/lib/vertesia-ui-features.js.map +1 -1
  215. package/lib/vertesia-ui-i18n.js +41 -2
  216. package/lib/vertesia-ui-i18n.js.map +1 -1
  217. package/lib/vertesia-ui-layout.js +2 -2
  218. package/lib/vertesia-ui-layout.js.map +1 -1
  219. package/lib/vertesia-ui-router.js +2 -2
  220. package/lib/vertesia-ui-router.js.map +1 -1
  221. package/lib/vertesia-ui-session.js +2 -2
  222. package/lib/vertesia-ui-session.js.map +1 -1
  223. package/lib/vertesia-ui-shell.js +2 -2
  224. package/lib/vertesia-ui-shell.js.map +1 -1
  225. package/lib/vertesia-ui-widgets.js +9 -2
  226. package/lib/vertesia-ui-widgets.js.map +1 -1
  227. package/lib/widgets/json-view/JSONCode.d.ts.map +1 -1
  228. package/lib/widgets/json-view/JSONCode.js +1 -1
  229. package/lib/widgets/json-view/JSONCode.js.map +1 -1
  230. package/lib/widgets/json-view/JSONTable.d.ts.map +1 -1
  231. package/lib/widgets/json-view/JSONTable.js +1 -1
  232. package/lib/widgets/json-view/JSONTable.js.map +1 -1
  233. package/lib/widgets/markdown/ArtifactContentRenderer.d.ts.map +1 -1
  234. package/lib/widgets/markdown/ArtifactContentRenderer.js +1 -1
  235. package/lib/widgets/markdown/ArtifactContentRenderer.js.map +1 -1
  236. package/lib/widgets/markdown/CodeBlockPlaceholder.d.ts.map +1 -1
  237. package/lib/widgets/markdown/CodeBlockPlaceholder.js +1 -1
  238. package/lib/widgets/markdown/CodeBlockPlaceholder.js.map +1 -1
  239. package/lib/widgets/monacoEditor/foldingProviders.d.ts.map +1 -1
  240. package/lib/widgets/monacoEditor/foldingProviders.js +5 -10
  241. package/lib/widgets/monacoEditor/foldingProviders.js.map +1 -1
  242. package/lib/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  243. package/lib/widgets/schema-editor/ManagedSchema.js +1 -2
  244. package/lib/widgets/schema-editor/ManagedSchema.js.map +1 -1
  245. package/lib/widgets/upload/UploadResultCategory.d.ts.map +1 -1
  246. package/lib/widgets/upload/UploadResultCategory.js +1 -1
  247. package/lib/widgets/upload/UploadResultCategory.js.map +1 -1
  248. package/lib/widgets/xml-viewer/components/TextElement/index.d.ts.map +1 -1
  249. package/lib/widgets/xml-viewer/components/TextElement/index.js +1 -1
  250. package/lib/widgets/xml-viewer/components/TextElement/index.js.map +1 -1
  251. package/package.json +38 -43
  252. package/src/core/components/InputList.tsx +5 -10
  253. package/src/core/components/SelectList.tsx +7 -2
  254. package/src/core/components/TagsInput.tsx +41 -4
  255. package/src/core/components/popup/Popup.tsx +3 -3
  256. package/src/core/components/popup/position.ts +3 -6
  257. package/src/core/components/shadcn/badge.tsx +3 -0
  258. package/src/core/components/shadcn/breadcrumb.tsx +2 -4
  259. package/src/core/components/shadcn/filters/filterBar.tsx +2 -3
  260. package/src/core/components/shadcn/resizeable.test.tsx +77 -0
  261. package/src/core/components/shadcn/resizeable.tsx +28 -2
  262. package/src/core/components/shadcn/selectBox.tsx +70 -36
  263. package/src/core/components/table/index.tsx +1 -2
  264. package/src/core/hooks/useIntersectionObserver.tsx +3 -1
  265. package/src/features/agent/chat/AgentRightPanel.tsx +5 -6
  266. package/src/features/agent/chat/AnimatedThinkingDots.tsx +1 -2
  267. package/src/features/agent/chat/AskUserWidget.test.tsx +49 -0
  268. package/src/features/agent/chat/AskUserWidget.tsx +32 -22
  269. package/src/features/agent/chat/ModernAgentConversation.test.tsx +198 -1
  270. package/src/features/agent/chat/ModernAgentConversation.tsx +62 -15
  271. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +60 -34
  272. package/src/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.tsx +3 -3
  273. package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +25 -0
  274. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +5 -1
  275. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +30 -30
  276. package/src/features/agent/chat/ModernAgentOutput/PlanPanel.tsx +5 -6
  277. package/src/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.tsx +4 -5
  278. package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +3 -5
  279. package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +326 -42
  280. package/src/features/agent/chat/hooks/useFileProcessing.test.tsx +70 -0
  281. package/src/features/agent/chat/hooks/useFileProcessing.ts +37 -6
  282. package/src/features/facets/AgentRunnerFacetsNav.tsx +1 -2
  283. package/src/features/facets/InteractionsFacetsNav.tsx +30 -5
  284. package/src/features/facets/PromptsFacetsNav.tsx +13 -1
  285. package/src/features/facets/RunsFacetsNav.tsx +1 -2
  286. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +1 -2
  287. package/src/features/magic-pdf/MagicPdfProvider.tsx +4 -4
  288. package/src/features/store/objects/DocumentSearchResults.tsx +11 -1
  289. package/src/features/store/objects/components/ContentOverview.tsx +1 -2
  290. package/src/features/store/objects/components/DocumentIcon.tsx +1 -2
  291. package/src/features/store/objects/components/DocumentInput.tsx +2 -2
  292. package/src/features/store/objects/search/DocumentSearchContext.test.ts +2 -2
  293. package/src/features/store/objects/search/DocumentSearchContext.ts +3 -3
  294. package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -27
  295. package/src/features/store/objects/selection/ObjectsActionContextClass.ts +1 -7
  296. package/src/features/store/objects/selection/ObjectsActionHooks.ts +0 -11
  297. package/src/features/store/objects/selection/SelectionActions.tsx +9 -34
  298. package/src/features/store/objects/selection/actions/DeleteObjectsAction.tsx +40 -7
  299. package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +104 -0
  300. package/src/features/store/objects/selection/actions/index.ts +0 -1
  301. package/src/features/store/types/ContentObjectTypesSearch.tsx +110 -1
  302. package/src/features/store/types/ContentObjectTypesTable.tsx +42 -3
  303. package/src/features/store/types/search/ObjectTypeSearchContext.tsx +1 -1
  304. package/src/i18n/locales/ar.json +17 -0
  305. package/src/i18n/locales/de.json +17 -0
  306. package/src/i18n/locales/en.json +33 -0
  307. package/src/i18n/locales/es.json +17 -0
  308. package/src/i18n/locales/fr.json +17 -0
  309. package/src/i18n/locales/it.json +17 -0
  310. package/src/i18n/locales/ja.json +17 -0
  311. package/src/i18n/locales/ko.json +17 -0
  312. package/src/i18n/locales/pt.json +17 -0
  313. package/src/i18n/locales/ru.json +17 -0
  314. package/src/i18n/locales/tr.json +17 -0
  315. package/src/i18n/locales/zh-TW.json +17 -0
  316. package/src/i18n/locales/zh.json +17 -0
  317. package/src/layout/Sidebar.tsx +6 -1
  318. package/src/router/NestedRouterProvider.tsx +2 -2
  319. package/src/router/Redirect.tsx +29 -0
  320. package/src/router/Router.tsx +1 -2
  321. package/src/router/index.ts +1 -0
  322. package/src/session/DevSessionProvider.tsx +46 -0
  323. package/src/session/UserSessionProvider.tsx +18 -2
  324. package/src/session/auth/composable.ts +41 -3
  325. package/src/session/index.ts +1 -0
  326. package/src/shell/VertesiaShell.tsx +27 -14
  327. package/src/shell/login/SignInRestrictedEnvStep.tsx +87 -0
  328. package/src/shell/login/SigninScreen.tsx +29 -16
  329. package/src/shell/login/productionUrl.test.ts +19 -0
  330. package/src/shell/login/productionUrl.ts +18 -0
  331. package/src/shell/login/signInUtils.ts +14 -1
  332. package/src/widgets/json-view/JSONCode.tsx +1 -2
  333. package/src/widgets/json-view/JSONTable.tsx +1 -2
  334. package/src/widgets/markdown/ArtifactContentRenderer.tsx +4 -7
  335. package/src/widgets/markdown/CodeBlockPlaceholder.tsx +1 -2
  336. package/src/widgets/monacoEditor/foldingProviders.ts +10 -15
  337. package/src/widgets/schema-editor/ManagedSchema.ts +1 -2
  338. package/src/widgets/upload/UploadResultCategory.tsx +2 -3
  339. package/src/widgets/xml-viewer/components/TextElement/index.tsx +1 -2
  340. package/lib/features/store/objects/selection/actions/StartWorkflowComponent.d.ts +0 -4
  341. package/lib/features/store/objects/selection/actions/StartWorkflowComponent.d.ts.map +0 -1
  342. package/lib/features/store/objects/selection/actions/StartWorkflowComponent.js +0 -77
  343. package/lib/features/store/objects/selection/actions/StartWorkflowComponent.js.map +0 -1
  344. package/src/features/store/objects/selection/actions/StartWorkflowComponent.tsx +0 -127
@@ -104,6 +104,8 @@ const VARIANT_ICONS = {
104
104
  success: CheckCircle,
105
105
  };
106
106
 
107
+ const SCROLLABLE_PROMPT_CLASS = 'max-h-80 overflow-y-auto overscroll-contain pe-2';
108
+
107
109
  /**
108
110
  * AskUserWidget - A styled component for displaying agent prompts/questions to users
109
111
  *
@@ -197,10 +199,14 @@ export function AskUserWidget({
197
199
  if (answered) {
198
200
  return (
199
201
  <div className={cn('my-1.5 font-sans', className)}>
200
- {compactQuestion}
201
- {description && (
202
- <p className={cn('mt-1 text-xs leading-5 text-muted', descriptionClassName)}>{description}</p>
203
- )}
202
+ <div className={SCROLLABLE_PROMPT_CLASS}>
203
+ {compactQuestion}
204
+ {description && (
205
+ <p className={cn('mt-1 text-xs leading-5 text-muted', descriptionClassName)}>
206
+ {description}
207
+ </p>
208
+ )}
209
+ </div>
204
210
  </div>
205
211
  );
206
212
  }
@@ -214,12 +220,14 @@ export function AskUserWidget({
214
220
  <div className={cn('mt-1 flex-shrink-0 text-attention', iconClassName)}>{iconNode}</div>
215
221
  )}
216
222
  <div className="min-w-0 flex-1">
217
- {compactQuestion}
218
- {description && (
219
- <p className={cn('mt-1 text-xs leading-5 text-muted', descriptionClassName)}>
220
- {description}
221
- </p>
222
- )}
223
+ <div className={SCROLLABLE_PROMPT_CLASS}>
224
+ {compactQuestion}
225
+ {description && (
226
+ <p className={cn('mt-1 text-xs leading-5 text-muted', descriptionClassName)}>
227
+ {description}
228
+ </p>
229
+ )}
230
+ </div>
223
231
  </div>
224
232
  </div>
225
233
  </div>
@@ -355,19 +363,21 @@ export function AskUserWidget({
355
363
  {icon || <DefaultIcon className="size-5" />}
356
364
  </div>
357
365
  )}
358
- <div className="flex-1 min-w-0">
359
- <div
360
- className={`prose prose-sm dark:prose-invert max-w-none text-gray-900 dark:text-gray-100 ${questionClassName || ''}`}
361
- >
362
- <MarkdownRenderer>{question}</MarkdownRenderer>
363
- </div>
364
- {description && (
365
- <p
366
- className={`mt-1 text-sm text-gray-600 dark:text-gray-400 ${descriptionClassName || ''}`}
366
+ <div className="min-w-0 flex-1">
367
+ <div className={SCROLLABLE_PROMPT_CLASS}>
368
+ <div
369
+ className={`agent-ask-question prose prose-sm dark:prose-invert max-w-none text-gray-900 dark:text-gray-100 ${questionClassName || ''}`}
367
370
  >
368
- {description}
369
- </p>
370
- )}
371
+ <MarkdownRenderer>{question}</MarkdownRenderer>
372
+ </div>
373
+ {description && (
374
+ <p
375
+ className={`mt-1 text-sm text-gray-600 dark:text-gray-400 ${descriptionClassName || ''}`}
376
+ >
377
+ {description}
378
+ </p>
379
+ )}
380
+ </div>
371
381
  </div>
372
382
  </div>
373
383
  </div>
@@ -1,5 +1,5 @@
1
1
  import { act, fireEvent, screen, waitFor } from '@testing-library/react';
2
- import { type AgentMessage, AgentMessageType } from '@vertesia/common';
2
+ import { type AgentMessage, AgentMessageType, type ConversationFile, FileProcessingStatus } from '@vertesia/common';
3
3
  import type React from 'react';
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
5
  import { renderWithProviders } from '../../../__tests__/test-utils.js';
@@ -245,6 +245,7 @@ describe('ModernAgentConversation send handling', () => {
245
245
  hasProcessingFiles: false,
246
246
  handleFileUpload: vi.fn(),
247
247
  removeProcessingFile: vi.fn(),
248
+ clearProcessingFiles: vi.fn(),
248
249
  });
249
250
  });
250
251
 
@@ -285,6 +286,53 @@ describe('ModernAgentConversation send handling', () => {
285
286
  expect(mocks.updateOptimisticMessageStatus).toHaveBeenCalledWith(expect.any(String), 'received');
286
287
  });
287
288
 
289
+ it('binds ready uploaded files into the sent message and clears them after send', async () => {
290
+ const clearProcessingFiles = vi.fn();
291
+ const readyFile: ConversationFile = {
292
+ id: 'file-1',
293
+ name: 'report.pdf',
294
+ content_type: 'application/pdf',
295
+ size: 10,
296
+ status: FileProcessingStatus.READY,
297
+ artifact_path: 'files/report.pdf',
298
+ reference: 'artifact:files/report.pdf',
299
+ started_at: 1_000,
300
+ };
301
+ mocks.useFileProcessing.mockReturnValue({
302
+ processingFiles: new Map([[readyFile.id, readyFile]]),
303
+ hasProcessingFiles: false,
304
+ handleFileUpload: vi.fn(),
305
+ removeProcessingFile: vi.fn(),
306
+ clearProcessingFiles,
307
+ });
308
+ mockStreamState({
309
+ messages: [createMessage(AgentMessageType.COMPLETE, 'done')],
310
+ agentRunStatus: 'COMPLETED',
311
+ });
312
+
313
+ renderConversation({ onRestart: vi.fn() });
314
+
315
+ fireEvent.click(screen.getByRole('button', { name: 'inline send' }));
316
+
317
+ await waitFor(() => {
318
+ expect(mocks.sendSignal).toHaveBeenCalledWith(
319
+ 'agent-run-1',
320
+ 'UserInput',
321
+ expect.objectContaining({
322
+ message: expect.stringContaining('Uploaded artifacts:'),
323
+ }),
324
+ );
325
+ });
326
+
327
+ const userInputCall = mocks.sendSignal.mock.calls.find((call) => call[1] === 'UserInput');
328
+ expect((userInputCall?.[2] as { message: string }).message).toContain(
329
+ '[report.pdf](artifact:files/report.pdf)',
330
+ );
331
+ await waitFor(() => {
332
+ expect(clearProcessingFiles).toHaveBeenCalledTimes(1);
333
+ });
334
+ });
335
+
288
336
  it('does not restart or send from a terminal run that cannot continue', () => {
289
337
  mockStreamState({
290
338
  messages: [createMessage(AgentMessageType.COMPLETE, 'done')],
@@ -425,6 +473,155 @@ describe('ModernAgentConversation send handling', () => {
425
473
  expect(screen.queryByText('Switch to full control?')).toBeNull();
426
474
  });
427
475
 
476
+ it('orders a follow-up user message after an in-flight approval mode change', async () => {
477
+ let resolveModeSignal: (() => void) | undefined;
478
+ mocks.retrieve.mockResolvedValue({
479
+ tool_approval_mode: 'ask',
480
+ interactive: true,
481
+ disabled_mcp_collections: undefined,
482
+ });
483
+ mocks.sendSignal.mockImplementation((_runId: string, signalName: string) => {
484
+ if (signalName === 'ToolApprovalModeChanged') {
485
+ return new Promise<void>((resolve) => {
486
+ resolveModeSignal = resolve;
487
+ });
488
+ }
489
+ return Promise.resolve({});
490
+ });
491
+ mockStreamState({
492
+ messages: [createMessage(AgentMessageType.REQUEST_INPUT, 'What should I do next?')],
493
+ isCompleted: false,
494
+ agentRunStatus: 'RUNNING',
495
+ });
496
+
497
+ renderConversation({ hideMessageInput: false, interactive: true, allowWorkflowControl: true });
498
+
499
+ const selector = await screen.findByRole('button', { name: 'Agent approval mode' });
500
+ fireEvent.pointerDown(selector, {
501
+ button: 0,
502
+ ctrlKey: false,
503
+ });
504
+ fireEvent.click(await screen.findByRole('menuitemradio', { name: /Full control/ }));
505
+
506
+ await waitFor(() => {
507
+ expect(mocks.sendSignal).toHaveBeenCalledWith('agent-run-1', 'ToolApprovalModeChanged', {
508
+ mode: 'full_control',
509
+ });
510
+ expect(resolveModeSignal).toBeDefined();
511
+ });
512
+
513
+ fireEvent.click(screen.getByRole('button', { name: 'composer send' }));
514
+
515
+ expect(mocks.sendSignal.mock.calls.some((call) => call[1] === 'UserInput')).toBe(false);
516
+
517
+ await act(async () => {
518
+ resolveModeSignal?.();
519
+ });
520
+
521
+ await waitFor(() => {
522
+ expect(mocks.sendSignal).toHaveBeenCalledWith(
523
+ 'agent-run-1',
524
+ 'UserInput',
525
+ expect.objectContaining({ message: 'follow up' }),
526
+ );
527
+ });
528
+
529
+ const modeCallIndex = mocks.sendSignal.mock.calls.findIndex((call) => call[1] === 'ToolApprovalModeChanged');
530
+ const userInputCallIndex = mocks.sendSignal.mock.calls.findIndex((call) => call[1] === 'UserInput');
531
+ expect(modeCallIndex).toBeGreaterThanOrEqual(0);
532
+ expect(userInputCallIndex).toBeGreaterThan(modeCallIndex);
533
+ });
534
+
535
+ it('keeps a local approval mode change when stale run metadata loads later', async () => {
536
+ let resolveRetrieve: (run: {
537
+ tool_approval_mode: 'ask';
538
+ interactive: true;
539
+ disabled_mcp_collections: undefined;
540
+ }) => void = () => {};
541
+ mocks.retrieve.mockReturnValue(
542
+ new Promise((resolve) => {
543
+ resolveRetrieve = resolve;
544
+ }),
545
+ );
546
+ mockStreamState({
547
+ messages: [createMessage(AgentMessageType.ANSWER, 'still running')],
548
+ isCompleted: false,
549
+ agentRunStatus: 'RUNNING',
550
+ });
551
+
552
+ renderConversation({
553
+ hideMessageInput: false,
554
+ interactive: true,
555
+ allowWorkflowControl: true,
556
+ initialToolApprovalMode: 'ask',
557
+ });
558
+
559
+ expect(await screen.findByText('Ask for approval')).not.toBeNull();
560
+ fireEvent.pointerDown(screen.getByRole('button', { name: 'Agent approval mode' }), {
561
+ button: 0,
562
+ ctrlKey: false,
563
+ });
564
+ fireEvent.click(await screen.findByRole('menuitemradio', { name: /Full control/ }));
565
+
566
+ await waitFor(() => {
567
+ expect(mocks.sendSignal).toHaveBeenCalledWith('agent-run-1', 'ToolApprovalModeChanged', {
568
+ mode: 'full_control',
569
+ });
570
+ });
571
+
572
+ resolveRetrieve({
573
+ tool_approval_mode: 'ask',
574
+ interactive: true,
575
+ disabled_mcp_collections: undefined,
576
+ });
577
+
578
+ await waitFor(() => {
579
+ expect(screen.getByText('Full control')).not.toBeNull();
580
+ });
581
+ });
582
+
583
+ it('reverts the local approval mode when the change signal fails', async () => {
584
+ let rejectSignal: (error: Error) => void = () => {};
585
+ mocks.retrieve.mockResolvedValue({
586
+ tool_approval_mode: 'ask',
587
+ interactive: true,
588
+ disabled_mcp_collections: undefined,
589
+ });
590
+ mocks.sendSignal.mockReturnValueOnce(
591
+ new Promise((_resolve, reject) => {
592
+ rejectSignal = reject;
593
+ }),
594
+ );
595
+ mockStreamState({
596
+ messages: [createMessage(AgentMessageType.ANSWER, 'still running')],
597
+ isCompleted: false,
598
+ agentRunStatus: 'RUNNING',
599
+ });
600
+
601
+ renderConversation({ hideMessageInput: false, interactive: true, allowWorkflowControl: true });
602
+
603
+ const selector = await screen.findByRole('button', { name: 'Agent approval mode' });
604
+ expect(selector.textContent).toContain('Ask for approval');
605
+ fireEvent.pointerDown(selector, {
606
+ button: 0,
607
+ ctrlKey: false,
608
+ });
609
+ fireEvent.click(await screen.findByRole('menuitemradio', { name: /Full control/ }));
610
+
611
+ await waitFor(() => {
612
+ expect(mocks.sendSignal).toHaveBeenCalledWith('agent-run-1', 'ToolApprovalModeChanged', {
613
+ mode: 'full_control',
614
+ });
615
+ expect(selector.textContent).toContain('Full control');
616
+ });
617
+
618
+ rejectSignal(new Error('Signal failed'));
619
+
620
+ await waitFor(() => {
621
+ expect(selector.textContent).toContain('Ask for approval');
622
+ });
623
+ });
624
+
428
625
  it('does not show a full-control fallback before active run mode metadata loads', () => {
429
626
  mocks.retrieve.mockReturnValue(new Promise(() => {}));
430
627
  mockStreamState({
@@ -7,6 +7,7 @@ import {
7
7
  type CompletedWorkstreamEntry,
8
8
  type ConversationFile,
9
9
  type ConversationFileRef,
10
+ FileProcessingStatus,
10
11
  type McpConnectUxConfig,
11
12
  normalizeAgentToolApprovalMode,
12
13
  type Plan,
@@ -1359,12 +1360,8 @@ function ModernAgentConversationInner({
1359
1360
  updateDocumentTitle,
1360
1361
  } = useDocumentPanel(messages);
1361
1362
 
1362
- const { processingFiles, hasProcessingFiles, handleFileUpload, removeProcessingFile } = useFileProcessing(
1363
- client,
1364
- agentRunId,
1365
- serverFileUpdates,
1366
- toast,
1367
- );
1363
+ const { processingFiles, hasProcessingFiles, handleFileUpload, removeProcessingFile, clearProcessingFiles } =
1364
+ useFileProcessing(client, agentRunId, serverFileUpdates, toast);
1368
1365
  const canUploadFiles = interactive && !hideFileUpload;
1369
1366
 
1370
1367
  const handleRemoveProcessingFile = useCallback(
@@ -1416,6 +1413,8 @@ function ModernAgentConversationInner({
1416
1413
  const workstreamFetchFailedRef = useRef(false);
1417
1414
  const dragCounterRef = useRef(0);
1418
1415
  const pendingPlaybackScrollRef = useRef(false);
1416
+ const toolApprovalModeChangeVersionRef = useRef(0);
1417
+ const pendingToolApprovalModeChangeRef = useRef<Promise<void> | null>(null);
1419
1418
 
1420
1419
  useEffect(() => {
1421
1420
  setToolApprovalMode(initialResolvedToolApprovalMode);
@@ -1426,6 +1425,8 @@ function ModernAgentConversationInner({
1426
1425
  isSendingRef.current = isSending;
1427
1426
  const hasProcessingFilesRef = useRef(hasProcessingFiles);
1428
1427
  hasProcessingFilesRef.current = hasProcessingFiles;
1428
+ const processingFilesRef = useRef(processingFiles);
1429
+ processingFilesRef.current = processingFiles;
1429
1430
 
1430
1431
  const lastMainMessage = useMemo(() => {
1431
1432
  const mainMessages = messages.filter((m) => (m.workstream_id || 'main') === 'main');
@@ -1909,6 +1910,13 @@ function ModernAgentConversationInner({
1909
1910
  // Handlers
1910
1911
  // ────────────────────────────────────────────
1911
1912
 
1913
+ const waitForPendingToolApprovalModeChange = useCallback(async () => {
1914
+ const pendingChange = pendingToolApprovalModeChangeRef.current;
1915
+ if (pendingChange) {
1916
+ await pendingChange;
1917
+ }
1918
+ }, []);
1919
+
1912
1920
  // Send a message to the agent
1913
1921
  const handleSendMessage = useCallback(
1914
1922
  (message: string, inputMetadata?: Record<string, unknown>) => {
@@ -1942,6 +1950,24 @@ function ModernAgentConversationInner({
1942
1950
  messageContent = [trimmed, '', 'Attachments:', ...lines].join('\n');
1943
1951
  }
1944
1952
 
1953
+ // Bind ready uploaded files to this message: embed them as an "Uploaded artifacts:"
1954
+ // markdown block so they render underneath the sent bubble (parsed by
1955
+ // parseUserMessageAttachments) and get cleared from the composer on send.
1956
+ const uploadedArtifactLines = Array.from(processingFilesRef.current.values())
1957
+ .filter((file) => file.status === FileProcessingStatus.READY)
1958
+ .map((file) => {
1959
+ const href = file.reference?.startsWith('artifact:')
1960
+ ? file.reference
1961
+ : file.artifact_path
1962
+ ? `artifact:${file.artifact_path}`
1963
+ : undefined;
1964
+ return href ? `[${file.name}](${href})` : undefined;
1965
+ })
1966
+ .filter((line): line is string => Boolean(line));
1967
+ if (uploadedArtifactLines.length > 0) {
1968
+ messageContent = [messageContent, '', 'Uploaded artifacts:', ...uploadedArtifactLines].join('\n');
1969
+ }
1970
+
1945
1971
  const messageId = `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1946
1972
 
1947
1973
  const optimisticMessage: AgentMessage = {
@@ -1973,6 +1999,7 @@ function ModernAgentConversationInner({
1973
1999
  const markReceived = () => {
1974
2000
  updateOptimisticMessageStatus(messageId, 'received');
1975
2001
  onAttachmentsSent?.();
2002
+ clearProcessingFiles();
1976
2003
  };
1977
2004
 
1978
2005
  // When the workflow has already completed, restart it first so it resumes
@@ -1980,12 +2007,15 @@ function ModernAgentConversationInner({
1980
2007
  // buffers the signal until the new run is ready to receive it. We reconnect
1981
2008
  // the stream in place (rather than remounting via onRestart) so the existing
1982
2009
  // timeline is preserved and the new exchange appends seamlessly at the bottom.
1983
- const deliver = isWorkflowTerminalRef.current
1984
- ? client.agents.restart(agentRunId).then(() => {
1985
- reconnectStream();
1986
- return sendUserInput().then(markReceived);
1987
- })
1988
- : sendUserInput().then(markReceived);
2010
+ const deliver = (async () => {
2011
+ await waitForPendingToolApprovalModeChange();
2012
+ if (isWorkflowTerminalRef.current) {
2013
+ await client.agents.restart(agentRunId);
2014
+ reconnectStream();
2015
+ }
2016
+ await sendUserInput();
2017
+ markReceived();
2018
+ })();
1989
2019
 
1990
2020
  deliver
1991
2021
  .catch((err) => {
@@ -2008,10 +2038,12 @@ function ModernAgentConversationInner({
2008
2038
  getAttachedDocs,
2009
2039
  getMessageContext,
2010
2040
  onAttachmentsSent,
2041
+ clearProcessingFiles,
2011
2042
  reconnectStream,
2012
2043
  addOptimisticMessage,
2013
2044
  updateOptimisticMessageStatus,
2014
2045
  t,
2046
+ waitForPendingToolApprovalModeChange,
2015
2047
  ],
2016
2048
  );
2017
2049
 
@@ -2040,12 +2072,16 @@ function ModernAgentConversationInner({
2040
2072
  const [mcpDisabled, setMcpDisabled] = useState<string[] | undefined>(undefined);
2041
2073
  useEffect(() => {
2042
2074
  let cancelled = false;
2075
+ const requestVersion = toolApprovalModeChangeVersionRef.current;
2043
2076
  client.agents
2044
2077
  .retrieve(agentRunId)
2045
2078
  .then((run) => {
2046
2079
  if (!cancelled) {
2047
2080
  setMcpDisabled(run.disabled_mcp_collections);
2048
- if (run.tool_approval_mode !== undefined || run.interactive !== undefined) {
2081
+ if (
2082
+ toolApprovalModeChangeVersionRef.current === requestVersion &&
2083
+ (run.tool_approval_mode !== undefined || run.interactive !== undefined)
2084
+ ) {
2049
2085
  setToolApprovalMode(normalizeAgentToolApprovalMode(run.tool_approval_mode, run.interactive));
2050
2086
  }
2051
2087
  }
@@ -2081,10 +2117,14 @@ function ModernAgentConversationInner({
2081
2117
  const handleToolApprovalModeChange = useCallback(
2082
2118
  (mode: AgentToolApprovalMode) => {
2083
2119
  const nextMode = normalizeAgentToolApprovalMode(mode, interactive);
2120
+ const previousMode = toolApprovalMode;
2121
+ toolApprovalModeChangeVersionRef.current += 1;
2084
2122
  setToolApprovalMode(nextMode);
2085
- client.agents
2123
+ const signalPromise = client.agents
2086
2124
  .sendSignal(agentRunId, 'ToolApprovalModeChanged', { mode: nextMode })
2125
+ .then(() => undefined)
2087
2126
  .catch((err: unknown) => {
2127
+ setToolApprovalMode((currentMode) => (currentMode === nextMode ? previousMode : currentMode));
2088
2128
  toast({
2089
2129
  status: 'error',
2090
2130
  title: t('agent.approvalMode.changeFailed'),
@@ -2092,8 +2132,14 @@ function ModernAgentConversationInner({
2092
2132
  duration: 3000,
2093
2133
  });
2094
2134
  });
2135
+ pendingToolApprovalModeChangeRef.current = signalPromise;
2136
+ void signalPromise.finally(() => {
2137
+ if (pendingToolApprovalModeChangeRef.current === signalPromise) {
2138
+ pendingToolApprovalModeChangeRef.current = null;
2139
+ }
2140
+ });
2095
2141
  },
2096
- [agentRunId, client, interactive, t, toast],
2142
+ [agentRunId, client, interactive, t, toast, toolApprovalMode],
2097
2143
  );
2098
2144
 
2099
2145
  // Drag and drop handlers for full-panel file upload
@@ -2418,6 +2464,7 @@ function ModernAgentConversationInner({
2418
2464
  ) : (
2419
2465
  <AllMessagesMixed
2420
2466
  messages={displayedMessages}
2467
+ workstreamSourceMessages={messages}
2421
2468
  bottomRef={bottomRef as React.RefObject<HTMLDivElement>}
2422
2469
  isCompleted={displayedIsCompleted}
2423
2470
  plan={getActivePlan.plan}
@@ -2328,8 +2328,43 @@ class MessageErrorBoundary extends Component<{ children: ReactNode }, { hasError
2328
2328
  }
2329
2329
  }
2330
2330
 
2331
+ // Sort chronologically, drop document-panel events + hidden types, and dedupe adjacent
2332
+ // identical messages. Shared by the rendered transcript and the workstream tab derivation.
2333
+ function sortAndDedupeMessages(messages: AgentMessage[], hiddenMessageTypes?: AgentMessageType[]): AgentMessage[] {
2334
+ const filtered = messages.filter(
2335
+ (message) => !isDocumentPanelEventMessage(message) && !hiddenMessageTypes?.includes(message.type),
2336
+ );
2337
+
2338
+ const sorted = [...filtered].sort((a, b) => {
2339
+ const timeA = typeof a.timestamp === 'number' ? a.timestamp : new Date(a.timestamp).getTime();
2340
+ const timeB = typeof b.timestamp === 'number' ? b.timestamp : new Date(b.timestamp).getTime();
2341
+ return timeA - timeB;
2342
+ });
2343
+
2344
+ const deduped: AgentMessage[] = [];
2345
+ for (const msg of sorted) {
2346
+ const previous = deduped[deduped.length - 1];
2347
+ if (previous && shouldCollapseAdjacentRenderedMessage(previous, msg)) {
2348
+ continue;
2349
+ }
2350
+
2351
+ if (previous && shouldDedupeAdjacentCompletedToolMessage(previous, msg)) {
2352
+ continue;
2353
+ }
2354
+ deduped.push(msg);
2355
+ }
2356
+ return deduped;
2357
+ }
2358
+
2331
2359
  interface AllMessagesMixedProps {
2332
2360
  messages: AgentMessage[];
2361
+ /**
2362
+ * Full, workstream-unfiltered message set used to derive the workstream tab list, per-tab
2363
+ * counts, and completion status. Falls back to `messages` when omitted. The parent filters
2364
+ * `messages` down to the active workstream, so deriving the tab list from `messages` alone
2365
+ * makes the tabs collapse (and vanish once `main` is selected) as you navigate between them.
2366
+ */
2367
+ workstreamSourceMessages?: AgentMessage[];
2333
2368
  bottomRef: React.RefObject<HTMLDivElement>;
2334
2369
  viewMode?: 'stacked' | 'sliding';
2335
2370
  isCompleted?: boolean;
@@ -2397,6 +2432,7 @@ const SCROLL_THROTTLE_MS = 100; // Max 10 scrolls per second
2397
2432
 
2398
2433
  function AllMessagesMixedComponent({
2399
2434
  messages,
2435
+ workstreamSourceMessages,
2400
2436
  bottomRef,
2401
2437
  viewMode = 'stacked',
2402
2438
  isCompleted = false,
@@ -2536,36 +2572,26 @@ function AllMessagesMixedComponent({
2536
2572
 
2537
2573
  // Sort all messages chronologically and dedupe adjacent identical messages
2538
2574
  // Low-signal messages are suppressed at the source (server-side) via shouldSuppressLowSignalMessage
2539
- const sortedMessages = React.useMemo(() => {
2540
- const filtered = messages.filter(
2541
- (message) => !isDocumentPanelEventMessage(message) && !hiddenMessageTypes?.includes(message.type),
2542
- );
2543
-
2544
- const sorted = [...filtered].sort((a, b) => {
2545
- const timeA = typeof a.timestamp === 'number' ? a.timestamp : new Date(a.timestamp).getTime();
2546
- const timeB = typeof b.timestamp === 'number' ? b.timestamp : new Date(b.timestamp).getTime();
2547
- return timeA - timeB;
2548
- });
2549
-
2550
- const deduped: AgentMessage[] = [];
2551
- for (const msg of sorted) {
2552
- const previous = deduped[deduped.length - 1];
2553
- if (previous && shouldCollapseAdjacentRenderedMessage(previous, msg)) {
2554
- continue;
2555
- }
2575
+ const sortedMessages = React.useMemo(
2576
+ () => sortAndDedupeMessages(messages, hiddenMessageTypes),
2577
+ [messages, hiddenMessageTypes],
2578
+ );
2556
2579
 
2557
- if (previous && shouldDedupeAdjacentCompletedToolMessage(previous, msg)) {
2558
- continue;
2559
- }
2560
- deduped.push(msg);
2561
- }
2562
- return deduped;
2563
- }, [messages, hiddenMessageTypes]);
2580
+ // The workstream tabs are navigation over the WHOLE conversation, so derive them from the
2581
+ // unfiltered source rather than `messages` (which the parent filters to the active workstream).
2582
+ // Falling back to `sortedMessages` keeps callers that don't pass the source working unchanged.
2583
+ const workstreamSourceSorted = React.useMemo(
2584
+ () =>
2585
+ workstreamSourceMessages
2586
+ ? sortAndDedupeMessages(workstreamSourceMessages, hiddenMessageTypes)
2587
+ : sortedMessages,
2588
+ [workstreamSourceMessages, hiddenMessageTypes, sortedMessages],
2589
+ );
2564
2590
 
2565
2591
  const workstreams = React.useMemo(() => {
2566
- const extractedWorkstreams = extractWorkstreams(sortedMessages);
2592
+ const extractedWorkstreams = extractWorkstreams(workstreamSourceSorted);
2567
2593
 
2568
- sortedMessages.forEach((message) => {
2594
+ workstreamSourceSorted.forEach((message) => {
2569
2595
  const details = getWorkstreamLaunchDetails(message) ?? getWorkstreamActivityDetails(message);
2570
2596
  if (!details) return;
2571
2597
  extractedWorkstreams.set(
@@ -2575,7 +2601,7 @@ function AllMessagesMixedComponent({
2575
2601
  });
2576
2602
 
2577
2603
  return extractedWorkstreams;
2578
- }, [sortedMessages]);
2604
+ }, [workstreamSourceSorted]);
2579
2605
 
2580
2606
  const activeWorkstreamName = React.useMemo(() => {
2581
2607
  if (activeWorkstream === 'all') return undefined;
@@ -2616,17 +2642,17 @@ function AllMessagesMixedComponent({
2616
2642
  }
2617
2643
  }, [activeWorkstream, workstreams, setActiveWorkstream]);
2618
2644
 
2619
- // Count messages per workstream
2645
+ // Count messages per workstream (from the full source so counts don't shrink to the active tab)
2620
2646
  const workstreamCounts = React.useMemo(() => {
2621
2647
  const counts = new Map<string, number>();
2622
- counts.set('all', sortedMessages.length);
2648
+ counts.set('all', workstreamSourceSorted.length);
2623
2649
 
2624
2650
  // Count main messages
2625
- const mainMessages = filterMessagesByWorkstream(sortedMessages, 'main');
2651
+ const mainMessages = filterMessagesByWorkstream(workstreamSourceSorted, 'main');
2626
2652
  counts.set('main', mainMessages.length);
2627
2653
 
2628
2654
  // Count other workstreams
2629
- sortedMessages.forEach((msg) => {
2655
+ workstreamSourceSorted.forEach((msg) => {
2630
2656
  const workstreamId = getWorkstreamId(msg);
2631
2657
  if (workstreamId !== 'main') {
2632
2658
  counts.set(workstreamId, (counts.get(workstreamId) || 0) + 1);
@@ -2634,7 +2660,7 @@ function AllMessagesMixedComponent({
2634
2660
  });
2635
2661
 
2636
2662
  return counts;
2637
- }, [sortedMessages]);
2663
+ }, [workstreamSourceSorted]);
2638
2664
 
2639
2665
  // Filter messages based on active workstream
2640
2666
  const displayMessages = React.useMemo(() => {
@@ -2869,7 +2895,7 @@ function AllMessagesMixedComponent({
2869
2895
  // Group messages by workstream
2870
2896
  const workstreamMessages = new Map<string, AgentMessage[]>();
2871
2897
 
2872
- sortedMessages.forEach((message) => {
2898
+ workstreamSourceSorted.forEach((message) => {
2873
2899
  const workstreamId = getWorkstreamId(message);
2874
2900
  if (!workstreamMessages.has(workstreamId)) {
2875
2901
  workstreamMessages.set(workstreamId, []);
@@ -2905,7 +2931,7 @@ function AllMessagesMixedComponent({
2905
2931
  }
2906
2932
 
2907
2933
  return statusMap;
2908
- }, [sortedMessages]);
2934
+ }, [workstreamSourceSorted]);
2909
2935
 
2910
2936
  return (
2911
2937
  <div
@@ -127,9 +127,9 @@ function InlineSlidingPlanPanelComponent({
127
127
  : `task-${taskGoal}-${task.status || 'pending'}`;
128
128
 
129
129
  let status: 'pending' | 'in_progress' | 'completed' | 'skipped' = task.status || 'pending';
130
- if (workstreamStatus.has(taskId)) {
131
- // biome-ignore lint/style/noNonNullAssertion: intentional non-null assertion; TS can't prove narrowing here
132
- status = workstreamStatus.get(taskId)!;
130
+ const wsStatus = workstreamStatus.get(taskId);
131
+ if (wsStatus !== undefined) {
132
+ status = wsStatus;
133
133
  }
134
134
 
135
135
  let StatusIcon = Circle;