@vertesia/ui 1.5.0-dev.20260910.052912Z → 1.6.0-dev.20260912.110338Z

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 (389) hide show
  1. package/README.md +125 -0
  2. package/lib/boot/branding.d.ts +58 -0
  3. package/lib/boot/branding.d.ts.map +1 -0
  4. package/lib/boot/branding.js +62 -0
  5. package/lib/boot/branding.js.map +1 -0
  6. package/lib/boot/index.d.ts +27 -0
  7. package/lib/boot/index.d.ts.map +1 -0
  8. package/lib/boot/index.js +325 -0
  9. package/lib/boot/index.js.map +1 -0
  10. package/lib/boot/vite.d.ts +63 -0
  11. package/lib/boot/vite.d.ts.map +1 -0
  12. package/lib/boot/vite.js +108 -0
  13. package/lib/boot/vite.js.map +1 -0
  14. package/lib/core/components/Link.js +1 -1
  15. package/lib/core/components/Link.js.map +1 -1
  16. package/lib/core/components/Spinner.js +1 -1
  17. package/lib/core/components/Spinner.js.map +1 -1
  18. package/lib/core/components/TagsInput.js +7 -7
  19. package/lib/core/components/TagsInput.js.map +1 -1
  20. package/lib/core/components/shadcn/badge.js +1 -1
  21. package/lib/core/components/shadcn/badge.js.map +1 -1
  22. package/lib/core/components/shadcn/button.d.ts.map +1 -1
  23. package/lib/core/components/shadcn/button.js +3 -4
  24. package/lib/core/components/shadcn/button.js.map +1 -1
  25. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +2 -2
  26. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
  27. package/lib/core/components/shadcn/filters/comboBox/SelectCombobox.js +1 -1
  28. package/lib/core/components/shadcn/filters/comboBox/SelectCombobox.js.map +1 -1
  29. package/lib/core/components/shadcn/filters/comboBox/StringListCombobox.js +1 -1
  30. package/lib/core/components/shadcn/filters/comboBox/StringListCombobox.js.map +1 -1
  31. package/lib/core/components/shadcn/filters/comboBox/TextCombobox.js +1 -1
  32. package/lib/core/components/shadcn/filters/comboBox/TextCombobox.js.map +1 -1
  33. package/lib/core/components/shadcn/filters/filter/dateFilter.js +1 -1
  34. package/lib/core/components/shadcn/filters/filter/dateFilter.js.map +1 -1
  35. package/lib/core/components/shadcn/filters/filter-styles.d.ts +1 -1
  36. package/lib/core/components/shadcn/filters/filter-styles.d.ts.map +1 -1
  37. package/lib/core/components/shadcn/filters/filter-styles.js +4 -4
  38. package/lib/core/components/shadcn/filters/filters.js +1 -1
  39. package/lib/core/components/shadcn/filters/filters.js.map +1 -1
  40. package/lib/core/components/shadcn/label.js +1 -1
  41. package/lib/core/components/shadcn/label.js.map +1 -1
  42. package/lib/core/components/shadcn/overflowTabs.js +2 -2
  43. package/lib/core/components/shadcn/overflowTabs.js.map +1 -1
  44. package/lib/core/components/shadcn/tabs.js +1 -1
  45. package/lib/core/components/shadcn/tabs.js.map +1 -1
  46. package/lib/env/index.d.ts +28 -1
  47. package/lib/env/index.d.ts.map +1 -1
  48. package/lib/env/index.js +51 -3
  49. package/lib/env/index.js.map +1 -1
  50. package/lib/features/activity-doc/ActivityDoc.js +1 -1
  51. package/lib/features/activity-doc/ActivityDoc.js.map +1 -1
  52. package/lib/features/agent/PayloadBuilder.d.ts +4 -0
  53. package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
  54. package/lib/features/agent/PayloadBuilder.js.map +1 -1
  55. package/lib/features/agent/chat/AgentRunFeedback.d.ts +59 -0
  56. package/lib/features/agent/chat/AgentRunFeedback.d.ts.map +1 -0
  57. package/lib/features/agent/chat/AgentRunFeedback.js +286 -0
  58. package/lib/features/agent/chat/AgentRunFeedback.js.map +1 -0
  59. package/lib/features/agent/chat/AskUserWidget.d.ts +1 -0
  60. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  61. package/lib/features/agent/chat/AskUserWidget.js +15 -4
  62. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  63. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  64. package/lib/features/agent/chat/ModernAgentConversation.js +3 -2
  65. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  66. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
  67. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  68. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +16 -13
  69. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  70. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  71. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  72. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
  73. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  74. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +30 -8
  75. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  76. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
  77. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +2 -0
  78. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
  79. package/lib/features/agent/chat/index.d.ts +1 -0
  80. package/lib/features/agent/chat/index.d.ts.map +1 -1
  81. package/lib/features/agent/chat/index.js +1 -0
  82. package/lib/features/agent/chat/index.js.map +1 -1
  83. package/lib/features/facets/AgentRunnerFacetsNav.d.ts +8 -0
  84. package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
  85. package/lib/features/facets/AgentRunnerFacetsNav.js +12 -0
  86. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  87. package/lib/features/layout/GenericPageNavHeader.js +1 -1
  88. package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
  89. package/lib/features/magic-pdf/AnnotatedImageSlider.js +1 -1
  90. package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
  91. package/lib/features/magic-pdf/GroundedExtractionView.js +3 -3
  92. package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
  93. package/lib/features/permissions/UserPermissionsProvider.d.ts +15 -1
  94. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  95. package/lib/features/permissions/UserPermissionsProvider.js +20 -12
  96. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  97. package/lib/features/store/objects/DocumentPreviewPanel.js +5 -5
  98. package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
  99. package/lib/features/store/objects/components/DocumentInput.js +1 -1
  100. package/lib/features/store/objects/components/DocumentInput.js.map +1 -1
  101. package/lib/features/store/objects/selection/SelectionActions.js +1 -1
  102. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  103. package/lib/features/store/objects/upload/DocumentUploadModal.js +1 -1
  104. package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  105. package/lib/features/store/types/TypeRegistry.d.ts +130 -0
  106. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  107. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +130 -0
  108. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  109. package/lib/features/user/UserInfo.js +1 -1
  110. package/lib/features/user/UserInfo.js.map +1 -1
  111. package/lib/i18n/index.d.ts +5 -4
  112. package/lib/i18n/index.d.ts.map +1 -1
  113. package/lib/i18n/index.js +16 -2
  114. package/lib/i18n/index.js.map +1 -1
  115. package/lib/i18n/locales/ar.json +30 -0
  116. package/lib/i18n/locales/de.json +30 -0
  117. package/lib/i18n/locales/en.json +30 -0
  118. package/lib/i18n/locales/es.json +30 -0
  119. package/lib/i18n/locales/fr.json +30 -0
  120. package/lib/i18n/locales/it.json +30 -0
  121. package/lib/i18n/locales/ja.json +30 -0
  122. package/lib/i18n/locales/ko.json +30 -0
  123. package/lib/i18n/locales/pt.json +30 -0
  124. package/lib/i18n/locales/ru.json +30 -0
  125. package/lib/i18n/locales/tr.json +30 -0
  126. package/lib/i18n/locales/zh-TW.json +30 -0
  127. package/lib/i18n/locales/zh.json +30 -0
  128. package/lib/layout/ErrorPage.js +1 -1
  129. package/lib/layout/ErrorPage.js.map +1 -1
  130. package/lib/layout/Navbar.d.ts.map +1 -1
  131. package/lib/layout/Navbar.js +3 -2
  132. package/lib/layout/Navbar.js.map +1 -1
  133. package/lib/router/RouteComponent.d.ts.map +1 -1
  134. package/lib/router/RouteComponent.js +15 -12
  135. package/lib/router/RouteComponent.js.map +1 -1
  136. package/lib/session/UserSession.d.ts.map +1 -1
  137. package/lib/session/UserSession.js +6 -3
  138. package/lib/session/UserSession.js.map +1 -1
  139. package/lib/session/UserSessionProvider.d.ts +2 -1
  140. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  141. package/lib/session/UserSessionProvider.js +10 -1
  142. package/lib/session/UserSessionProvider.js.map +1 -1
  143. package/lib/session/auth/composable.d.ts.map +1 -1
  144. package/lib/session/auth/composable.js +88 -3
  145. package/lib/session/auth/composable.js.map +1 -1
  146. package/lib/session/auth/domainRouting.d.ts +22 -12
  147. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  148. package/lib/session/auth/domainRouting.js +35 -21
  149. package/lib/session/auth/domainRouting.js.map +1 -1
  150. package/lib/session/auth/useAuthState.d.ts +9 -4
  151. package/lib/session/auth/useAuthState.d.ts.map +1 -1
  152. package/lib/session/auth/useAuthState.js +9 -4
  153. package/lib/session/auth/useAuthState.js.map +1 -1
  154. package/lib/session/index.d.ts.map +1 -1
  155. package/lib/session/index.js +3 -1
  156. package/lib/session/index.js.map +1 -1
  157. package/lib/shell/AuthScreenPreview.d.ts +12 -0
  158. package/lib/shell/AuthScreenPreview.d.ts.map +1 -0
  159. package/lib/shell/AuthScreenPreview.js +140 -0
  160. package/lib/shell/AuthScreenPreview.js.map +1 -0
  161. package/lib/shell/BrandedAuthScreens.d.ts +19 -0
  162. package/lib/shell/BrandedAuthScreens.d.ts.map +1 -0
  163. package/lib/shell/BrandedAuthScreens.js +64 -0
  164. package/lib/shell/BrandedAuthScreens.js.map +1 -0
  165. package/lib/shell/SplashScreen.d.ts +13 -2
  166. package/lib/shell/SplashScreen.d.ts.map +1 -1
  167. package/lib/shell/SplashScreen.js +21 -20
  168. package/lib/shell/SplashScreen.js.map +1 -1
  169. package/lib/shell/VertesiaShell.d.ts +15 -4
  170. package/lib/shell/VertesiaShell.d.ts.map +1 -1
  171. package/lib/shell/VertesiaShell.js +8 -3
  172. package/lib/shell/VertesiaShell.js.map +1 -1
  173. package/lib/shell/apps/StandaloneApp.js +5 -1
  174. package/lib/shell/apps/StandaloneApp.js.map +1 -1
  175. package/lib/shell/index.d.ts +6 -0
  176. package/lib/shell/index.d.ts.map +1 -1
  177. package/lib/shell/index.js +5 -0
  178. package/lib/shell/index.js.map +1 -1
  179. package/lib/shell/login/SignInFlow.d.ts +68 -0
  180. package/lib/shell/login/SignInFlow.d.ts.map +1 -0
  181. package/lib/shell/login/SignInFlow.js +108 -0
  182. package/lib/shell/login/SignInFlow.js.map +1 -0
  183. package/lib/shell/login/SignInPageShell.d.ts +13 -0
  184. package/lib/shell/login/SignInPageShell.d.ts.map +1 -0
  185. package/lib/shell/login/SignInPageShell.js +14 -0
  186. package/lib/shell/login/SignInPageShell.js.map +1 -0
  187. package/lib/shell/login/SignInPrimitives.d.ts +3 -3
  188. package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
  189. package/lib/shell/login/SignInPrimitives.js +13 -11
  190. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  191. package/lib/shell/login/SignInRestrictedEnvStep.d.ts +5 -0
  192. package/lib/shell/login/SignInRestrictedEnvStep.d.ts.map +1 -1
  193. package/lib/shell/login/SignInRestrictedEnvStep.js +8 -4
  194. package/lib/shell/login/SignInRestrictedEnvStep.js.map +1 -1
  195. package/lib/shell/login/SigninScreen.d.ts +38 -3
  196. package/lib/shell/login/SigninScreen.d.ts.map +1 -1
  197. package/lib/shell/login/SigninScreen.js +33 -86
  198. package/lib/shell/login/SigninScreen.js.map +1 -1
  199. package/lib/shell/login/SignupForm.d.ts +3 -1
  200. package/lib/shell/login/SignupForm.d.ts.map +1 -1
  201. package/lib/shell/login/SignupForm.js +7 -3
  202. package/lib/shell/login/SignupForm.js.map +1 -1
  203. package/lib/shell/login/signInUtils.d.ts +11 -0
  204. package/lib/shell/login/signInUtils.d.ts.map +1 -1
  205. package/lib/shell/login/signInUtils.js +29 -5
  206. package/lib/shell/login/signInUtils.js.map +1 -1
  207. package/lib/vertesia-ui-boot.js +237 -0
  208. package/lib/vertesia-ui-boot.js.map +1 -0
  209. package/lib/vertesia-ui-core.js +46 -46
  210. package/lib/vertesia-ui-core.js.map +1 -1
  211. package/lib/vertesia-ui-env.js +1 -1
  212. package/lib/vertesia-ui-env.js.map +1 -1
  213. package/lib/vertesia-ui-features.js +222 -208
  214. package/lib/vertesia-ui-features.js.map +1 -1
  215. package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js +5 -0
  216. package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js.map +1 -0
  217. package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js +5 -0
  218. package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js.map +1 -0
  219. package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js +5 -0
  220. package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js.map +1 -0
  221. package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js +5 -0
  222. package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js.map +1 -0
  223. package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js +5 -0
  224. package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js.map +1 -0
  225. package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js +5 -0
  226. package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js.map +1 -0
  227. package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js +5 -0
  228. package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js.map +1 -0
  229. package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js +5 -0
  230. package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js.map +1 -0
  231. package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js +5 -0
  232. package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js.map +1 -0
  233. package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js +5 -0
  234. package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js.map +1 -0
  235. package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js +5 -0
  236. package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js.map +1 -0
  237. package/lib/vertesia-ui-i18n.js +2 -2
  238. package/lib/vertesia-ui-i18n.js.map +1 -1
  239. package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js +5 -0
  240. package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js.map +1 -0
  241. package/lib/vertesia-ui-layout.js +13 -13
  242. package/lib/vertesia-ui-layout.js.map +1 -1
  243. package/lib/vertesia-ui-rich-text.js +68 -68
  244. package/lib/vertesia-ui-rich-text.js.map +1 -1
  245. package/lib/vertesia-ui-router.js +1 -1
  246. package/lib/vertesia-ui-router.js.map +1 -1
  247. package/lib/vertesia-ui-session.js +1 -1
  248. package/lib/vertesia-ui-session.js.map +1 -1
  249. package/lib/vertesia-ui-shell.js +58 -33
  250. package/lib/vertesia-ui-shell.js.map +1 -1
  251. package/lib/vertesia-ui-widgets.js +94 -94
  252. package/lib/vertesia-ui-widgets.js.map +1 -1
  253. package/lib/widgets/json-view/JSONCode.js +1 -1
  254. package/lib/widgets/json-view/JSONCode.js.map +1 -1
  255. package/lib/widgets/upload/DropZone.d.ts.map +1 -1
  256. package/lib/widgets/upload/DropZone.js +1 -1
  257. package/lib/widgets/upload/DropZone.js.map +1 -1
  258. package/llms.txt +6 -2
  259. package/package.json +44 -35
  260. package/src/__tests__/a11y.test.tsx +25 -0
  261. package/src/__tests__/theme.test.ts +91 -0
  262. package/src/boot/branding.test.ts +72 -0
  263. package/src/boot/branding.ts +108 -0
  264. package/src/boot/index.test.ts +216 -0
  265. package/src/boot/index.ts +356 -0
  266. package/src/boot/vite.test.ts +93 -0
  267. package/src/boot/vite.ts +118 -0
  268. package/src/core/components/Link.tsx +1 -1
  269. package/src/core/components/Spinner.tsx +1 -1
  270. package/src/core/components/TagsInput.tsx +7 -7
  271. package/src/core/components/shadcn/badge.tsx +1 -1
  272. package/src/core/components/shadcn/button.tsx +3 -5
  273. package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +2 -2
  274. package/src/core/components/shadcn/filters/comboBox/SelectCombobox.tsx +1 -1
  275. package/src/core/components/shadcn/filters/comboBox/StringListCombobox.tsx +1 -1
  276. package/src/core/components/shadcn/filters/comboBox/TextCombobox.tsx +1 -1
  277. package/src/core/components/shadcn/filters/filter/dateFilter.tsx +1 -1
  278. package/src/core/components/shadcn/filters/filter-styles.ts +4 -4
  279. package/src/core/components/shadcn/filters/filters.tsx +1 -1
  280. package/src/core/components/shadcn/label.tsx +1 -1
  281. package/src/core/components/shadcn/overflowTabs.tsx +2 -2
  282. package/src/core/components/shadcn/tabs.tsx +1 -1
  283. package/src/css/utilities.css +7 -0
  284. package/src/env/index.test.ts +100 -0
  285. package/src/env/index.ts +66 -3
  286. package/src/features/activity-doc/ActivityDoc.tsx +1 -1
  287. package/src/features/agent/PayloadBuilder.tsx +4 -0
  288. package/src/features/agent/chat/AgentRunFeedback.test.tsx +330 -0
  289. package/src/features/agent/chat/AgentRunFeedback.tsx +452 -0
  290. package/src/features/agent/chat/AskUserWidget.test.tsx +24 -2
  291. package/src/features/agent/chat/AskUserWidget.tsx +19 -4
  292. package/src/features/agent/chat/ModernAgentConversation.tsx +46 -42
  293. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +207 -0
  294. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +50 -31
  295. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +4 -0
  296. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +42 -8
  297. package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +2 -0
  298. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +14 -0
  299. package/src/features/agent/chat/hooks/useFileProcessing.test.tsx +0 -5
  300. package/src/features/agent/chat/index.ts +6 -0
  301. package/src/features/facets/AgentRunnerFacetsNav.tsx +26 -0
  302. package/src/features/layout/GenericPageNavHeader.test.tsx +36 -0
  303. package/src/features/layout/GenericPageNavHeader.tsx +1 -1
  304. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +1 -1
  305. package/src/features/magic-pdf/GroundedExtractionView.tsx +3 -3
  306. package/src/features/permissions/UserPermissionsProvider.test.tsx +50 -1
  307. package/src/features/permissions/UserPermissionsProvider.tsx +82 -44
  308. package/src/features/store/objects/DocumentPreviewPanel.tsx +10 -10
  309. package/src/features/store/objects/components/DocumentInput.tsx +1 -1
  310. package/src/features/store/objects/selection/SelectionActions.tsx +4 -1
  311. package/src/features/store/objects/upload/DocumentUploadModal.tsx +1 -1
  312. package/src/features/user/UserInfo.tsx +1 -1
  313. package/src/i18n/index.tsx +25 -2
  314. package/src/i18n/locales/ar.json +30 -0
  315. package/src/i18n/locales/de.json +30 -0
  316. package/src/i18n/locales/en.json +30 -0
  317. package/src/i18n/locales/es.json +30 -0
  318. package/src/i18n/locales/fr.json +30 -0
  319. package/src/i18n/locales/it.json +30 -0
  320. package/src/i18n/locales/ja.json +30 -0
  321. package/src/i18n/locales/ko.json +30 -0
  322. package/src/i18n/locales/pt.json +30 -0
  323. package/src/i18n/locales/ru.json +30 -0
  324. package/src/i18n/locales/tr.json +30 -0
  325. package/src/i18n/locales/zh-TW.json +30 -0
  326. package/src/i18n/locales/zh.json +30 -0
  327. package/src/layout/ErrorPage.tsx +1 -1
  328. package/src/layout/Navbar.test.tsx +58 -0
  329. package/src/layout/Navbar.tsx +5 -2
  330. package/src/router/RouteComponent.test.tsx +65 -1
  331. package/src/router/RouteComponent.tsx +18 -15
  332. package/src/session/UserSession.test.ts +65 -0
  333. package/src/session/UserSession.ts +6 -4
  334. package/src/session/UserSessionProvider.strict-mode.test.tsx +44 -0
  335. package/src/session/UserSessionProvider.test.ts +62 -1
  336. package/src/session/UserSessionProvider.tsx +9 -1
  337. package/src/session/auth/composable.renewal.test.ts +170 -0
  338. package/src/session/auth/composable.test.ts +23 -1
  339. package/src/session/auth/composable.ts +101 -2
  340. package/src/session/auth/domainRouting.test.ts +35 -65
  341. package/src/session/auth/domainRouting.ts +51 -34
  342. package/src/session/auth/useAuthState.ts +11 -4
  343. package/src/session/index.ts +3 -1
  344. package/src/shell/AuthScreenPreview.test.tsx +44 -0
  345. package/src/shell/AuthScreenPreview.tsx +228 -0
  346. package/src/shell/BrandedAuthScreens.test.tsx +181 -0
  347. package/src/shell/BrandedAuthScreens.tsx +117 -0
  348. package/src/shell/SplashScreen.test.tsx +37 -0
  349. package/src/shell/SplashScreen.tsx +45 -40
  350. package/src/shell/VertesiaShell.tsx +49 -22
  351. package/src/shell/apps/StandaloneApp.tsx +5 -1
  352. package/src/shell/index.tsx +6 -0
  353. package/src/shell/login/SignInFlow.tsx +213 -0
  354. package/src/shell/login/SignInPageShell.tsx +62 -0
  355. package/src/shell/login/SignInPrimitives.tsx +14 -11
  356. package/src/shell/login/SignInRestrictedEnvStep.tsx +19 -7
  357. package/src/shell/login/SigninScreen.test.tsx +104 -0
  358. package/src/shell/login/SigninScreen.tsx +115 -145
  359. package/src/shell/login/SignupForm.tsx +8 -3
  360. package/src/shell/login/signInUtils.ts +30 -5
  361. package/src/widgets/json-view/JSONCode.test.tsx +2 -2
  362. package/src/widgets/json-view/JSONCode.tsx +1 -1
  363. package/src/widgets/markdown/markdown.css +21 -21
  364. package/src/widgets/upload/DropZone.tsx +2 -4
  365. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +0 -5
  366. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +0 -1
  367. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +0 -5
  368. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +0 -1
  369. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +0 -5
  370. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +0 -1
  371. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +0 -5
  372. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +0 -1
  373. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +0 -5
  374. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +0 -1
  375. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +0 -5
  376. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +0 -1
  377. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +0 -5
  378. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +0 -1
  379. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +0 -5
  380. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +0 -1
  381. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +0 -5
  382. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +0 -1
  383. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +0 -5
  384. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +0 -1
  385. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +0 -5
  386. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +0 -1
  387. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +0 -5
  388. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +0 -1
  389. package/src/session/auth/authState.test.ts +0 -35
@@ -818,6 +818,105 @@ describe('AllMessagesMixed summary view', () => {
818
818
  expect(screen.getByText('Main agent response.')).not.toBeNull();
819
819
  });
820
820
 
821
+ it('keeps the existing back action visible for an empty selected workstream', () => {
822
+ renderSummary([
823
+ makeMessage({
824
+ timestamp: 1_000,
825
+ type: AgentMessageType.QUESTION,
826
+ message: 'Implement a type for a contract.',
827
+ }),
828
+ makeMessage({
829
+ timestamp: 2_000,
830
+ type: AgentMessageType.UPDATE,
831
+ message: 'Workstream "app_development_process" launched',
832
+ workstream_id: 'app_development_process',
833
+ details: {
834
+ event_class: 'activity',
835
+ workstream_event: 'launched',
836
+ launch_id: 'launch-process',
837
+ workstream_id: 'app_development_process',
838
+ kind: 'process',
839
+ process_run_id: 'process-run-1',
840
+ process_workflow_id: 'process-wf-1',
841
+ process_name: 'App Development Process',
842
+ },
843
+ }),
844
+ makeMessage({
845
+ timestamp: 3_000,
846
+ type: AgentMessageType.ANSWER,
847
+ message: 'Main agent response.',
848
+ }),
849
+ ]);
850
+
851
+ fireEvent.click(screen.getByRole('button', { name: /App Development Process/ }));
852
+
853
+ expect(screen.getByRole('button', { name: 'Back to main agent' })).not.toBeNull();
854
+ expect(screen.getByText('No messages in this workstream yet...')).not.toBeNull();
855
+
856
+ fireEvent.click(screen.getByRole('button', { name: 'Back to main agent' }));
857
+
858
+ expect(screen.getByText('Main agent response.')).not.toBeNull();
859
+ });
860
+
861
+ it('renders relayed Process progress in the selected workstream', () => {
862
+ renderSummary([
863
+ makeMessage({
864
+ timestamp: 1_000,
865
+ type: AgentMessageType.QUESTION,
866
+ message: 'Implement a type for a contract.',
867
+ }),
868
+ makeMessage({
869
+ timestamp: 2_000,
870
+ type: AgentMessageType.UPDATE,
871
+ message: 'Workstream "app_development_process" launched',
872
+ workstream_id: 'app_development_process',
873
+ details: {
874
+ event_class: 'activity',
875
+ workstream_event: 'launched',
876
+ launch_id: 'launch-process',
877
+ workstream_id: 'app_development_process',
878
+ kind: 'process',
879
+ process_run_id: 'process-run-1',
880
+ process_workflow_id: 'process-wf-1',
881
+ process_name: 'App Development Process',
882
+ },
883
+ }),
884
+ makeMessage({
885
+ timestamp: 3_000,
886
+ type: AgentMessageType.UPDATE,
887
+ message: 'Process running at implementation (agent, sequence 2).',
888
+ workstream_id: 'app_development_process',
889
+ details: {
890
+ event_class: 'activity',
891
+ process_event: 'progress',
892
+ launch_id: 'launch-process',
893
+ workstream_id: 'app_development_process',
894
+ kind: 'process',
895
+ process_run_id: 'process-run-1',
896
+ process_workflow_id: 'process-wf-1',
897
+ process_name: 'App Development Process',
898
+ phase: 'executing_tool',
899
+ current_step: 'implementation',
900
+ process_status: 'running',
901
+ process_current_node: 'implementation',
902
+ process_current_node_type: 'agent',
903
+ process_sequence: 2,
904
+ },
905
+ }),
906
+ makeMessage({
907
+ timestamp: 4_000,
908
+ type: AgentMessageType.ANSWER,
909
+ message: 'Main agent response.',
910
+ }),
911
+ ]);
912
+
913
+ fireEvent.click(screen.getByRole('button', { name: /App Development Process/ }));
914
+
915
+ expect(screen.getByRole('button', { name: 'Back to main agent' })).not.toBeNull();
916
+ expect(screen.getByText('Process running at implementation (agent, sequence 2).')).not.toBeNull();
917
+ expect(screen.queryByText('Main agent response.')).toBeNull();
918
+ });
919
+
821
920
  it('keeps streamed and persisted child output in the owning workstream throughout its lifecycle', () => {
822
921
  const question = makeMessage({
823
922
  timestamp: 1_000,
@@ -1599,6 +1698,68 @@ describe('AllMessagesMixed summary view', () => {
1599
1698
  expect(screen.getAllByText(/quotes\.md/).length).toBeGreaterThan(0);
1600
1699
  });
1601
1700
 
1701
+ describe.each(['summary', 'stacked', 'activity'] as const)('request input in %s view', (mode) => {
1702
+ function renderPrompt(options: unknown) {
1703
+ const onSendMessage = vi.fn();
1704
+ const prompt = makeMessage({
1705
+ timestamp: 2_000,
1706
+ type: AgentMessageType.REQUEST_INPUT,
1707
+ message: 'Choose a response',
1708
+ details: { request_id: 'robust-ask', ux: { options, variant: 'default', multiSelect: false } },
1709
+ });
1710
+ if (mode === 'stacked') {
1711
+ renderStacked([prompt], false, { onSendMessage });
1712
+ } else if (mode === 'activity') {
1713
+ renderSummary(
1714
+ [
1715
+ makeMessage({
1716
+ timestamp: 1_000,
1717
+ message: 'Waiting for input',
1718
+ details: {
1719
+ event_class: 'activity',
1720
+ tool: 'ask_user',
1721
+ tool_run_id: 'ask-run',
1722
+ tool_status: 'running',
1723
+ activity_group_id: 'ask-group',
1724
+ },
1725
+ }),
1726
+ { ...prompt, details: { ...prompt.details, activity_group_id: 'ask-group', tool: 'ask_user' } },
1727
+ makeMessage({ timestamp: 3_000, message: 'Finished', type: AgentMessageType.COMPLETE }),
1728
+ ],
1729
+ true,
1730
+ new Map(),
1731
+ { onSendMessage },
1732
+ );
1733
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
1734
+ } else {
1735
+ renderSummary([prompt], false, new Map(), { onSendMessage });
1736
+ }
1737
+ return onSendMessage;
1738
+ }
1739
+
1740
+ it.each([
1741
+ { name: 'a string', options: 'null' },
1742
+ { name: 'null', options: null },
1743
+ { name: 'a null entry', options: [null] },
1744
+ { name: 'an object label', options: [{ id: 'a', label: {} }] },
1745
+ { name: 'mixed valid and invalid entries', options: [{ id: 'a', label: 'A' }, null] },
1746
+ ])('allows text submission for $name', ({ options }) => {
1747
+ const onSendMessage = renderPrompt(options);
1748
+ fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Custom response' } });
1749
+ fireEvent.click(screen.getByRole('button', { name: 'Send' }));
1750
+ expect(onSendMessage).toHaveBeenCalledWith('Custom response', {
1751
+ request_input_response: { request_id: 'robust-ask' },
1752
+ });
1753
+ });
1754
+
1755
+ it('preserves valid choices and their response IDs', () => {
1756
+ const onSendMessage = renderPrompt([{ id: 'a', label: 'Choice A' }]);
1757
+ fireEvent.click(screen.getByRole('button', { name: 'Choice A' }));
1758
+ expect(onSendMessage).toHaveBeenCalledWith('a', { request_input_response: { request_id: 'robust-ask' } });
1759
+ expect(screen.queryByRole('textbox')).toBeNull();
1760
+ });
1761
+ });
1762
+
1602
1763
  it('renders pending ask options compactly in summary view', () => {
1603
1764
  renderSummary([
1604
1765
  makeMessage({
@@ -2720,3 +2881,49 @@ describe('AllMessagesMixed resource summary — same-timestamp cursor clipping',
2720
2881
  expect(screen.queryByText('Doc B')).toBeNull();
2721
2882
  });
2722
2883
  });
2884
+
2885
+ describe('AllMessagesMixed — answer feedback', () => {
2886
+ const answer = makeMessage({ type: AgentMessageType.ANSWER, message: 'Here is the result.', timestamp: 10 });
2887
+ const thought = makeMessage({ type: AgentMessageType.UPDATE, message: 'Working on it.', timestamp: 5 });
2888
+
2889
+ it('renders the rating control under each answer in the details view when a run id is given', () => {
2890
+ renderStacked([thought, answer], true, { agentRunId: 'agent-run-1' });
2891
+
2892
+ expect(screen.getByRole('button', { name: 'Rate this answer up' })).not.toBeNull();
2893
+ expect(screen.getByRole('button', { name: 'Rate this answer down' })).not.toBeNull();
2894
+ // Only answers are rated; the working update above it carries no control.
2895
+ expect(screen.getAllByRole('button', { name: /Rate this answer/ })).toHaveLength(2);
2896
+ });
2897
+
2898
+ it('renders the rating control under each answer in the summary view when a run id is given', () => {
2899
+ const session = new UserSession({} as unknown as VertesiaClient);
2900
+ const bottomRef = React.createRef<HTMLDivElement>() as React.RefObject<HTMLDivElement>;
2901
+ render(
2902
+ <I18nProvider lng="en">
2903
+ <ReactRouterContext.Provider value={makeRouterContext()}>
2904
+ <UserSessionContext.Provider value={session}>
2905
+ <AgentResourceResolverProvider value={testResourceResolver}>
2906
+ <AllMessagesMixed
2907
+ messages={[thought, answer]}
2908
+ bottomRef={bottomRef}
2909
+ viewMode="sliding"
2910
+ isCompleted
2911
+ artifactRunId="run-1"
2912
+ agentRunId="agent-run-1"
2913
+ />
2914
+ </AgentResourceResolverProvider>
2915
+ </UserSessionContext.Provider>
2916
+ </ReactRouterContext.Provider>
2917
+ </I18nProvider>,
2918
+ );
2919
+
2920
+ expect(screen.getByRole('button', { name: 'Rate this answer up' })).not.toBeNull();
2921
+ expect(screen.getAllByRole('button', { name: /Rate this answer/ })).toHaveLength(2);
2922
+ });
2923
+
2924
+ it('renders no rating control without a run id (fixture playback)', () => {
2925
+ renderStacked([thought, answer], true);
2926
+
2927
+ expect(screen.queryByRole('button', { name: /Rate this answer/ })).toBeNull();
2928
+ });
2929
+ });
@@ -29,8 +29,9 @@ import {
29
29
  Wrench,
30
30
  } from 'lucide-react';
31
31
  import React, { Component, type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
32
+ import { AgentRunFeedback, agentMessageFeedbackId } from '../AgentRunFeedback';
32
33
  import { AnimatedThinkingDots, PulsatingCircle } from '../AnimatedThinkingDots';
33
- import { AskUserWidget } from '../AskUserWidget';
34
+ import { AskUserWidget, isAskUserOptions } from '../AskUserWidget';
34
35
  import { DocumentEditingActionCard, parseMarkdownEditingAction } from '../DocumentEditingActionCard.js';
35
36
  import { ThinkingMessages } from '../WaitingMessages';
36
37
  import {
@@ -309,6 +310,8 @@ interface SummaryMessageProps {
309
310
  requestInputAnswered?: boolean;
310
311
  StoreLinkComponent?: React.ComponentType<{ href: string; documentId: string; children: React.ReactNode }>;
311
312
  CollectionLinkComponent?: React.ComponentType<{ href: string; collectionId: string; children: React.ReactNode }>;
313
+ /** When set, answers carry a thumbs up / down rating control scoped to the message. */
314
+ feedbackAgentRunId?: string;
312
315
  }
313
316
 
314
317
  function SummaryWorkstreamLaunchMessage({
@@ -677,6 +680,7 @@ function SummaryMessage({
677
680
  requestInputAnswered = false,
678
681
  StoreLinkComponent,
679
682
  CollectionLinkComponent,
683
+ feedbackAgentRunId,
680
684
  }: SummaryMessageProps) {
681
685
  const { router } = useRouterContext();
682
686
  const content =
@@ -758,11 +762,12 @@ function SummaryMessage({
758
762
  const requestInputDetails = message.details as AskUserMessageDetails | undefined;
759
763
  if (message.type === AgentMessageType.REQUEST_INPUT && requestInputDetails?.ux) {
760
764
  const uxConfig = requestInputDetails.ux;
765
+ const hasSelectableOptions = isAskUserOptions(uxConfig.options) && uxConfig.options.length > 0;
761
766
  return (
762
767
  <div className="mx-auto w-full max-w-3xl px-1">
763
768
  <AskUserWidget
764
769
  question={content}
765
- options={uxConfig.options}
770
+ options={hasSelectableOptions ? uxConfig.options : undefined}
766
771
  variant={uxConfig.variant}
767
772
  multiSelect={uxConfig.multiSelect}
768
773
  onSelect={(optionId) =>
@@ -776,7 +781,7 @@ function SummaryMessage({
776
781
  onMultiSelect={(optionIds) =>
777
782
  sendRequestInputResponse(onSendMessage, message, optionIds.join(', '))
778
783
  }
779
- allowFreeResponse={!uxConfig.options?.length || !!uxConfig.free_response}
784
+ allowFreeResponse={!hasSelectableOptions || !!uxConfig.free_response}
780
785
  placeholder={uxConfig.free_response?.placeholder}
781
786
  submitLabel={uxConfig.free_response?.submit_label}
782
787
  onSubmit={(value) =>
@@ -793,7 +798,7 @@ function SummaryMessage({
793
798
  const isError = message.type === AgentMessageType.ERROR || message.type === AgentMessageType.WARNING;
794
799
 
795
800
  return (
796
- <div className="mx-auto w-full max-w-3xl px-1" data-workstream-id={workstreamId}>
801
+ <div className="group mx-auto w-full max-w-3xl px-1" data-workstream-id={workstreamId}>
797
802
  {isError && (
798
803
  <div className="mb-2 text-xs font-medium text-destructive">
799
804
  {message.type === AgentMessageType.WARNING ? 'Warning' : 'Error'}
@@ -818,6 +823,14 @@ function SummaryMessage({
818
823
  </MarkdownRenderer>
819
824
  </div>
820
825
  )}
826
+ {feedbackAgentRunId && message.type === AgentMessageType.ANSWER && (
827
+ <AgentRunFeedback
828
+ agentRunId={feedbackAgentRunId}
829
+ messageId={agentMessageFeedbackId(message)}
830
+ tone="inline"
831
+ className="mt-1 -ms-1.5 print:hidden"
832
+ />
833
+ )}
821
834
  </div>
822
835
  );
823
836
  }
@@ -2300,11 +2313,13 @@ function SummaryActivityRow({
2300
2313
  <div className="mt-3 space-y-3">
2301
2314
  {requestInputMessages.map((message) => {
2302
2315
  const uxConfig = message.details.ux;
2316
+ const hasSelectableOptions =
2317
+ isAskUserOptions(uxConfig.options) && uxConfig.options.length > 0;
2303
2318
  return (
2304
2319
  <AskUserWidget
2305
2320
  key={getAgentMessageRenderKey(message, 'work-request-input')}
2306
2321
  question={getRequestInputDisplayText(message)}
2307
- options={uxConfig.options}
2322
+ options={hasSelectableOptions ? uxConfig.options : undefined}
2308
2323
  variant={uxConfig.variant}
2309
2324
  multiSelect={uxConfig.multiSelect}
2310
2325
  onSelect={(optionId) =>
@@ -2322,9 +2337,7 @@ function SummaryActivityRow({
2322
2337
  optionIds.join(', '),
2323
2338
  )
2324
2339
  }
2325
- allowFreeResponse={
2326
- !uxConfig.options?.length || !!uxConfig.free_response
2327
- }
2340
+ allowFreeResponse={!hasSelectableOptions || !!uxConfig.free_response}
2328
2341
  placeholder={uxConfig.free_response?.placeholder}
2329
2342
  submitLabel={uxConfig.free_response?.submit_label}
2330
2343
  onSubmit={(value) =>
@@ -2479,6 +2492,8 @@ interface AllMessagesMixedProps {
2479
2492
  batchProgressPanelClassNames?: BatchProgressPanelClassNames;
2480
2493
  /** Run ID used to resolve artifact references in streaming chart specs */
2481
2494
  artifactRunId?: string;
2495
+ /** Agent run to record answer ratings against. Omit to render answers without a rating control. */
2496
+ agentRunId?: string;
2482
2497
  /** Hide the workstream tabs entirely */
2483
2498
  hideWorkstreamTabs?: boolean;
2484
2499
  /** className override for the working indicator container */
@@ -2533,6 +2548,7 @@ function AllMessagesMixedComponent({
2533
2548
  streamingMessageClassNames,
2534
2549
  batchProgressPanelClassNames,
2535
2550
  artifactRunId,
2551
+ agentRunId,
2536
2552
  hideWorkstreamTabs,
2537
2553
  workingIndicatorClassName,
2538
2554
  messageListClassName,
@@ -3173,7 +3189,7 @@ function AllMessagesMixedComponent({
3173
3189
  padding: 0.75rem;
3174
3190
  border-radius: 0.5rem;
3175
3191
  overflow-x: auto;
3176
- background-color: var(--color-muted-background, #f3f4f6);
3192
+ background-color: var(--color-muted, #f3f4f6);
3177
3193
  color: var(--color-foreground, #1f2937);
3178
3194
  }
3179
3195
  .vprose pre code {
@@ -3268,7 +3284,7 @@ function AllMessagesMixedComponent({
3268
3284
  .agent-markdown :not(pre) > code {
3269
3285
  border: 1px solid var(--border);
3270
3286
  border-radius: 0.375rem;
3271
- background: var(--muted-background);
3287
+ background: var(--muted);
3272
3288
  color: var(--foreground);
3273
3289
  padding: 0.1rem 0.35rem;
3274
3290
  font-size: 0.8125em;
@@ -3281,7 +3297,7 @@ function AllMessagesMixedComponent({
3281
3297
  overflow: auto;
3282
3298
  border: 1px solid var(--border);
3283
3299
  border-radius: 0.75rem;
3284
- background: var(--muted-background);
3300
+ background: var(--muted);
3285
3301
  color: var(--foreground);
3286
3302
  padding: 0.875rem;
3287
3303
  font-size: 0.8125rem;
@@ -3369,6 +3385,27 @@ function AllMessagesMixedComponent({
3369
3385
  </div>
3370
3386
  )}
3371
3387
 
3388
+ {isSummaryView && activeWorkstream !== 'all' && activeWorkstreamName && (
3389
+ <div className="sticky top-0 z-20 -mx-2 bg-background/95 px-2 pb-2 pt-1 backdrop-blur sm:-mx-4 sm:px-4">
3390
+ <div className="mx-auto flex w-full max-w-3xl items-center gap-2 border-b border-border/70 pb-3">
3391
+ <Button
3392
+ type="button"
3393
+ variant="ghost"
3394
+ size="icon"
3395
+ className="size-8 shrink-0 text-muted hover:text-foreground"
3396
+ title={t('agent.backToMainAgent')}
3397
+ aria-label={t('agent.backToMainAgent')}
3398
+ onClick={handleShowMainAgentChat}
3399
+ >
3400
+ <ArrowLeft className="size-4" aria-hidden="true" />
3401
+ </Button>
3402
+ <div className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
3403
+ {activeWorkstreamName}
3404
+ </div>
3405
+ </div>
3406
+ </div>
3407
+ )}
3408
+
3372
3409
  {displayMessages.length === 0 &&
3373
3410
  incompleteStreaming.length === 0 &&
3374
3411
  !hasRenderableInitialRequest &&
@@ -3398,26 +3435,6 @@ function AllMessagesMixedComponent({
3398
3435
  messageListClassName,
3399
3436
  )}
3400
3437
  >
3401
- {isSummaryView && activeWorkstream !== 'all' && activeWorkstreamName && (
3402
- <div className="sticky top-0 z-20 -mx-2 bg-background/95 px-2 pb-2 pt-1 backdrop-blur sm:-mx-4 sm:px-4">
3403
- <div className="mx-auto flex w-full max-w-3xl items-center gap-2 border-b border-border/70 pb-3">
3404
- <Button
3405
- type="button"
3406
- variant="ghost"
3407
- size="icon"
3408
- className="size-8 shrink-0 text-muted hover:text-foreground"
3409
- title={t('agent.backToMainAgent')}
3410
- onClick={handleShowMainAgentChat}
3411
- >
3412
- <ArrowLeft className="size-4" aria-hidden="true" />
3413
- </Button>
3414
- <div className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
3415
- {activeWorkstreamName}
3416
- </div>
3417
- </div>
3418
- </div>
3419
- )}
3420
-
3421
3438
  {/* Friendly message — rendered outside the messages array to avoid memo issues/triggering autoscroll */}
3422
3439
  {shouldRenderInitialRequest && (
3423
3440
  <InitialRequestMessage
@@ -3587,6 +3604,7 @@ function AllMessagesMixedComponent({
3587
3604
  messageStyleOverrides={messageStyleOverrides}
3588
3605
  StoreLinkComponent={StoreLinkComponent}
3589
3606
  CollectionLinkComponent={CollectionLinkComponent}
3607
+ feedbackAgentRunId={agentRunId}
3590
3608
  />
3591
3609
  </MessageErrorBoundary>
3592
3610
  </TimelineEntry>
@@ -3707,6 +3725,7 @@ function AllMessagesMixedComponent({
3707
3725
  )}
3708
3726
  StoreLinkComponent={StoreLinkComponent}
3709
3727
  CollectionLinkComponent={CollectionLinkComponent}
3728
+ feedbackAgentRunId={agentRunId}
3710
3729
  />
3711
3730
  </MessageErrorBoundary>
3712
3731
  );
@@ -209,6 +209,10 @@ export default function Header({
209
209
  </Button>
210
210
  )}
211
211
 
212
+ {/* Keyed by run so a switch remounts the control. The component also resets itself —
213
+ it is exported and cannot assume a parent does this — but a remount here makes the
214
+ intent local and obvious at the one site that knows a new run is being shown. */}
215
+
212
216
  {agentRunId && (
213
217
  <Button
214
218
  type="button"
@@ -27,8 +27,9 @@ import type React from 'react';
27
27
  import { memo, useEffect, useMemo, useRef, useState } from 'react';
28
28
  import dayjs from '../../../../core/utils/dayjs.js';
29
29
  import { useDownloadFile } from '../../../store/objects/components/useDownloadFile.js';
30
+ import { AgentRunFeedback, agentMessageFeedbackId } from '../AgentRunFeedback';
30
31
  import { PulsatingCircle } from '../AnimatedThinkingDots';
31
- import { AskUserWidget } from '../AskUserWidget';
32
+ import { AskUserWidget, isAskUserOptions } from '../AskUserWidget';
32
33
  import { DocumentEditingActionCard, parseMarkdownEditingAction } from '../DocumentEditingActionCard.js';
33
34
  import { useImageLightbox } from '../ImageLightbox';
34
35
  import { getArtifactCacheKey, useArtifactUrlCache } from '../useArtifactUrlCache.js';
@@ -120,25 +121,42 @@ export interface MessageItemProps extends MessageItemClassNames {
120
121
  StoreLinkComponent?: React.ComponentType<{ href: string; documentId: string; children: React.ReactNode }>;
121
122
  /** Custom component to render store/collection links instead of default NavLink navigation */
122
123
  CollectionLinkComponent?: React.ComponentType<{ href: string; collectionId: string; children: React.ReactNode }>;
124
+ /** When set, answers carry a thumbs up / down rating control scoped to the message. */
125
+ feedbackAgentRunId?: string;
123
126
  }
124
127
 
125
128
  // Consolidated Studio/default message styling - single source of truth
126
129
  export const MESSAGE_STYLES: Record<AgentMessageType | 'default', MessageStyleConfig> = {
127
- [AgentMessageType.ANSWER]: { borderColor: 'border-s-info', iconColor: 'text-info', sender: 'Agent', Icon: Bot },
130
+ [AgentMessageType.ANSWER]: {
131
+ borderColor: 'border-s-info',
132
+ iconColor: 'text-info',
133
+ sender: 'Agent',
134
+ Icon: Bot,
135
+ },
128
136
  [AgentMessageType.COMPLETE]: {
129
137
  borderColor: 'border-s-success',
130
138
  iconColor: 'text-success',
131
139
  sender: 'Completed',
132
140
  Icon: CheckCircle,
133
141
  },
134
- [AgentMessageType.IDLE]: { borderColor: 'border-s-info', iconColor: 'text-info', sender: 'Ready', Icon: Clock },
142
+ [AgentMessageType.IDLE]: {
143
+ borderColor: 'border-s-info',
144
+ iconColor: 'text-info',
145
+ sender: 'Ready',
146
+ Icon: Clock,
147
+ },
135
148
  [AgentMessageType.REQUEST_INPUT]: {
136
149
  borderColor: 'border-s-attention',
137
150
  iconColor: 'text-attention',
138
151
  sender: 'Input',
139
152
  Icon: User,
140
153
  },
141
- [AgentMessageType.QUESTION]: { borderColor: 'border-s-muted', iconColor: 'text-muted', sender: 'User', Icon: User },
154
+ [AgentMessageType.QUESTION]: {
155
+ borderColor: 'border-s-muted',
156
+ iconColor: 'text-muted',
157
+ sender: 'User',
158
+ Icon: User,
159
+ },
142
160
  [AgentMessageType.THOUGHT]: {
143
161
  borderColor: 'border-s-done',
144
162
  iconColor: 'text-done',
@@ -175,7 +193,12 @@ export const MESSAGE_STYLES: Record<AgentMessageType | 'default', MessageStyleCo
175
193
  sender: 'Warning',
176
194
  Icon: AlertCircle,
177
195
  },
178
- [AgentMessageType.SYSTEM]: { borderColor: 'border-s-muted', iconColor: 'text-muted', sender: 'System', Icon: Info },
196
+ [AgentMessageType.SYSTEM]: {
197
+ borderColor: 'border-s-muted',
198
+ iconColor: 'text-muted',
199
+ sender: 'System',
200
+ Icon: Info,
201
+ },
179
202
  [AgentMessageType.STREAMING_CHUNK]: {
180
203
  borderColor: 'border-s-info',
181
204
  iconColor: 'text-info',
@@ -216,6 +239,7 @@ function MessageItemComponent({
216
239
  messageStyleOverrides,
217
240
  StoreLinkComponent,
218
241
  CollectionLinkComponent,
242
+ feedbackAgentRunId,
219
243
  }: MessageItemProps) {
220
244
  const [showDetails, setShowDetails] = useState(false);
221
245
  const { t } = useUITranslation();
@@ -375,6 +399,7 @@ function MessageItemComponent({
375
399
  // UX config for REQUEST_INPUT messages (narrowed const so it stays typed inside the JSX closures below)
376
400
  const askUserUx =
377
401
  message.type === AgentMessageType.REQUEST_INPUT ? (message.details as AskUserMessageDetails)?.ux : undefined;
402
+ const hasSelectableAskUserOptions = isAskUserOptions(askUserUx?.options) && askUserUx.options.length > 0;
378
403
 
379
404
  // PERFORMANCE: Memoize markdown components to prevent MarkdownRenderer remounts
380
405
  const markdownComponents = useMemo(
@@ -548,7 +573,7 @@ function MessageItemComponent({
548
573
  <div className={cn('w-full max-w-full', resolvedStyle.className)}>
549
574
  <div
550
575
  className={cn(
551
- 'border-s-4 bg-white dark:bg-muted mb-4 w-full max-w-full overflow-hidden',
576
+ 'group border-s-4 bg-white dark:bg-muted mb-4 w-full max-w-full overflow-hidden',
552
577
  resolvedStyle.borderColor,
553
578
  resolvedStyle.cardClassName,
554
579
  )}
@@ -616,7 +641,7 @@ function MessageItemComponent({
616
641
  {askUserUx ? (
617
642
  <AskUserWidget
618
643
  question={typeof messageContent === 'string' ? messageContent : ''}
619
- options={askUserUx.options}
644
+ options={hasSelectableAskUserOptions ? askUserUx.options : undefined}
620
645
  variant={askUserUx.variant}
621
646
  multiSelect={askUserUx.multiSelect}
622
647
  onSelect={(optionId) =>
@@ -630,7 +655,7 @@ function MessageItemComponent({
630
655
  onMultiSelect={(optionIds) =>
631
656
  sendRequestInputResponse(onSendMessage, message, optionIds.join(', '))
632
657
  }
633
- allowFreeResponse={!askUserUx.options?.length || !!askUserUx.free_response}
658
+ allowFreeResponse={!hasSelectableAskUserOptions || !!askUserUx.free_response}
634
659
  placeholder={askUserUx.free_response?.placeholder}
635
660
  submitLabel={askUserUx.free_response?.submit_label}
636
661
  onSubmit={(value) =>
@@ -658,6 +683,15 @@ function MessageItemComponent({
658
683
  )
659
684
  )}
660
685
 
686
+ {feedbackAgentRunId && message.type === AgentMessageType.ANSWER && (
687
+ <AgentRunFeedback
688
+ agentRunId={feedbackAgentRunId}
689
+ messageId={agentMessageFeedbackId(message)}
690
+ tone="inline"
691
+ className="mt-2 -ms-1.5 print:hidden"
692
+ />
693
+ )}
694
+
661
695
  {messageAttachments.length > 0 && (
662
696
  <AttachmentPreviewList
663
697
  items={messageAttachments}
@@ -133,6 +133,8 @@ export function isSummaryAssistantProseMessage(message: AgentMessage): boolean {
133
133
 
134
134
  if (message.type === AgentMessageType.ANSWER) return true;
135
135
 
136
+ if (message.details?.process_event === 'progress' && message.details?.kind === 'process') return true;
137
+
136
138
  if (isToolPreambleMessage(message)) {
137
139
  // Text accompanying ask_user can be the draft the question asks the user to review.
138
140
  // Keep it visible for both persisted messages and reconstructed streaming messages.
@@ -141,6 +141,20 @@ describe('ModernAgentOutput utils - tool preamble behavior', () => {
141
141
  });
142
142
 
143
143
  describe('ModernAgentOutput summary - ask_user review content', () => {
144
+ it('preserves process progress visibility alongside tool preamble classification', () => {
145
+ const progress = makeMessage({
146
+ message: 'The process completed its review step.',
147
+ details: {
148
+ process_event: 'progress',
149
+ kind: 'process',
150
+ display_role: 'tool_preamble',
151
+ tools: ['update_plan'],
152
+ },
153
+ });
154
+
155
+ expect(buildSummaryConversationItems([progress], false)).toEqual([{ type: 'message', message: progress }]);
156
+ });
157
+
144
158
  const draft = '## Draft agenda\n9:00 Welcome\n9:15 Platform foundations';
145
159
  const tool = makeMessage({
146
160
  timestamp: 3000,
@@ -149,11 +149,6 @@ describe('useFileProcessing', () => {
149
149
 
150
150
  await act(async () => {
151
151
  resolveUpload?.({ url: 'https://example.test/upload', path: 'files/wrong.png' });
152
- // biome 2.5.6 regression: the nursery rule mis-types `await` on a `Promise | undefined`
153
- // variable assigned inside a callback, and its own fix suggests `await await`. It only
154
- // fires on Linux CI, not on macOS, so the suppression may read as unused locally.
155
- // Drop it once the rule is fixed upstream.
156
- // biome-ignore lint/nursery/noFloatingPromises: false positive — already awaited
157
152
  await uploadPromise;
158
153
  });
159
154
 
@@ -28,6 +28,12 @@ export {
28
28
  type AgentChatReplayStreamingMessage,
29
29
  } from './AgentChatFixtureReplay';
30
30
  export { AgentChatPlaybackControls, type AgentChatPlaybackControlsProps } from './AgentChatPlaybackControls';
31
+ export {
32
+ AgentRunFeedback,
33
+ type AgentRunFeedbackProps,
34
+ AgentRunFeedbackProvider,
35
+ agentRunFeedbackReasonCodes,
36
+ } from './AgentRunFeedback';
31
37
  export * from './AnimatedThinkingDots';
32
38
  // AskUser widget for displaying agent prompts/questions
33
39
  export {