@vertesia/ui 1.4.0-dev.20260615.051508Z → 1.4.0-dev.20260629.130134Z

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 (337) hide show
  1. package/lib/core/components/shadcn/dropdown.d.ts.map +1 -1
  2. package/lib/core/components/shadcn/dropdown.js +6 -2
  3. package/lib/core/components/shadcn/dropdown.js.map +1 -1
  4. package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  5. package/lib/core/components/shadcn/filters/filterBar.js +9 -2
  6. package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
  7. package/lib/core/components/shadcn/modal/ConfirmModal.d.ts +16 -1
  8. package/lib/core/components/shadcn/modal/ConfirmModal.d.ts.map +1 -1
  9. package/lib/core/components/shadcn/modal/ConfirmModal.js +25 -3
  10. package/lib/core/components/shadcn/modal/ConfirmModal.js.map +1 -1
  11. package/lib/core/components/shadcn/modal/dialog.js +1 -1
  12. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  13. package/lib/core/components/shadcn/popover.d.ts.map +1 -1
  14. package/lib/core/components/shadcn/popover.js +3 -1
  15. package/lib/core/components/shadcn/popover.js.map +1 -1
  16. package/lib/core/components/shadcn/switch.js +3 -3
  17. package/lib/core/components/shadcn/switch.js.map +1 -1
  18. package/lib/core/components/shadcn/tabs.js +1 -1
  19. package/lib/core/components/shadcn/tabs.js.map +1 -1
  20. package/lib/core/components/shadcn/tooltip.d.ts.map +1 -1
  21. package/lib/core/components/shadcn/tooltip.js +3 -1
  22. package/lib/core/components/shadcn/tooltip.js.map +1 -1
  23. package/lib/env/index.d.ts +0 -19
  24. package/lib/env/index.d.ts.map +1 -1
  25. package/lib/env/index.js +0 -6
  26. package/lib/env/index.js.map +1 -1
  27. package/lib/features/agent/PayloadBuilder.d.ts +4 -0
  28. package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
  29. package/lib/features/agent/PayloadBuilder.js +16 -0
  30. package/lib/features/agent/PayloadBuilder.js.map +1 -1
  31. package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts +10 -0
  32. package/lib/features/agent/chat/AgentApprovalModeSelector.d.ts.map +1 -0
  33. package/lib/features/agent/chat/AgentApprovalModeSelector.js +50 -0
  34. package/lib/features/agent/chat/AgentApprovalModeSelector.js.map +1 -0
  35. package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts +2 -1
  36. package/lib/features/agent/chat/AgentChatFixtureReplay.d.ts.map +1 -1
  37. package/lib/features/agent/chat/AgentChatFixtureReplay.js +3 -3
  38. package/lib/features/agent/chat/AgentChatFixtureReplay.js.map +1 -1
  39. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +5 -2
  40. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
  41. package/lib/features/agent/chat/AgentRequestInputOverlay.js +41 -7
  42. package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
  43. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  44. package/lib/features/agent/chat/AgentRightPanel.js +133 -12
  45. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  46. package/lib/features/agent/chat/AnimatedThinkingDots.js +1 -1
  47. package/lib/features/agent/chat/AnimatedThinkingDots.js.map +1 -1
  48. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  49. package/lib/features/agent/chat/ArtifactsTab.js +11 -65
  50. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  51. package/lib/features/agent/chat/AskUserWidget.d.ts +3 -1
  52. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  53. package/lib/features/agent/chat/AskUserWidget.js +4 -3
  54. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  55. package/lib/features/agent/chat/ModernAgentConversation.d.ts +10 -2
  56. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  57. package/lib/features/agent/chat/ModernAgentConversation.js +526 -117
  58. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  59. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +8 -0
  60. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -0
  61. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +19 -0
  62. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -0
  63. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +8 -2
  64. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  65. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +551 -92
  66. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  67. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
  68. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +7 -6
  69. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
  70. package/lib/features/agent/chat/ModernAgentOutput/Header.js +2 -2
  71. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  72. package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts +8 -0
  73. package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.d.ts.map +1 -0
  74. package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js +61 -0
  75. package/lib/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.js.map +1 -0
  76. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +15 -2
  77. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  78. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +28 -38
  79. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  80. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +1 -1
  81. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  82. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +3 -2
  83. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  84. package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js +2 -1
  85. package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js.map +1 -1
  86. package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js +1 -1
  87. package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
  88. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts +5 -0
  89. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
  90. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +59 -4
  91. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
  92. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +2 -2
  93. package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
  94. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -0
  95. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
  96. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +180 -0
  97. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
  98. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +6 -0
  99. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
  100. package/lib/features/agent/chat/ModernAgentOutput/utils.js +92 -2
  101. package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
  102. package/lib/features/agent/chat/clipboardFiles.d.ts +15 -0
  103. package/lib/features/agent/chat/clipboardFiles.d.ts.map +1 -0
  104. package/lib/features/agent/chat/clipboardFiles.js +35 -0
  105. package/lib/features/agent/chat/clipboardFiles.js.map +1 -0
  106. package/lib/features/agent/chat/hooks/useAgentStream.d.ts +6 -0
  107. package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  108. package/lib/features/agent/chat/hooks/useAgentStream.js +218 -37
  109. package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  110. package/lib/features/agent/chat/hooks/useArtifacts.d.ts +1 -8
  111. package/lib/features/agent/chat/hooks/useArtifacts.d.ts.map +1 -1
  112. package/lib/features/agent/chat/hooks/useArtifacts.js +10 -28
  113. package/lib/features/agent/chat/hooks/useArtifacts.js.map +1 -1
  114. package/lib/features/agent/chat/index.d.ts +2 -1
  115. package/lib/features/agent/chat/index.d.ts.map +1 -1
  116. package/lib/features/agent/chat/index.js +2 -1
  117. package/lib/features/agent/chat/index.js.map +1 -1
  118. package/lib/features/agent/chat/workstreams.d.ts +1 -0
  119. package/lib/features/agent/chat/workstreams.d.ts.map +1 -1
  120. package/lib/features/agent/chat/workstreams.js +28 -0
  121. package/lib/features/agent/chat/workstreams.js.map +1 -1
  122. package/lib/features/facets/AgentRunnerFacetsNav.d.ts +10 -1
  123. package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
  124. package/lib/features/facets/AgentRunnerFacetsNav.js +6 -3
  125. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  126. package/lib/features/facets/CollectionsFacetsNav.d.ts +10 -1
  127. package/lib/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
  128. package/lib/features/facets/CollectionsFacetsNav.js +14 -5
  129. package/lib/features/facets/CollectionsFacetsNav.js.map +1 -1
  130. package/lib/features/facets/PromptsFacetsNav.d.ts +10 -1
  131. package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
  132. package/lib/features/facets/PromptsFacetsNav.js +14 -5
  133. package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
  134. package/lib/features/facets/RunsFacetsNav.d.ts +10 -1
  135. package/lib/features/facets/RunsFacetsNav.d.ts.map +1 -1
  136. package/lib/features/facets/RunsFacetsNav.js +14 -5
  137. package/lib/features/facets/RunsFacetsNav.js.map +1 -1
  138. package/lib/features/index.d.ts +0 -1
  139. package/lib/features/index.d.ts.map +1 -1
  140. package/lib/features/index.js +0 -1
  141. package/lib/features/index.js.map +1 -1
  142. package/lib/features/oauth/McpConnectionsButton.d.ts +30 -0
  143. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -0
  144. package/lib/features/oauth/McpConnectionsButton.js +70 -0
  145. package/lib/features/oauth/McpConnectionsButton.js.map +1 -0
  146. package/lib/features/oauth/McpConnectionsDialog.d.ts +25 -0
  147. package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -0
  148. package/lib/features/oauth/McpConnectionsDialog.js +26 -0
  149. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -0
  150. package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
  151. package/lib/features/oauth/RemoteMcpConnectionButton.js +14 -6
  152. package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
  153. package/lib/features/oauth/index.d.ts +3 -0
  154. package/lib/features/oauth/index.d.ts.map +1 -1
  155. package/lib/features/oauth/index.js +3 -0
  156. package/lib/features/oauth/index.js.map +1 -1
  157. package/lib/features/oauth/useMcpConnections.d.ts +44 -0
  158. package/lib/features/oauth/useMcpConnections.d.ts.map +1 -0
  159. package/lib/features/oauth/useMcpConnections.js +168 -0
  160. package/lib/features/oauth/useMcpConnections.js.map +1 -0
  161. package/lib/features/permissions/UserPermissionsProvider.d.ts +4 -6
  162. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  163. package/lib/features/permissions/UserPermissionsProvider.js +40 -42
  164. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  165. package/lib/features/store/objects/DocumentPreviewPanel.d.ts.map +1 -1
  166. package/lib/features/store/objects/DocumentPreviewPanel.js +2 -1
  167. package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
  168. package/lib/features/store/objects/DocumentQuickFilter.d.ts +23 -0
  169. package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -0
  170. package/lib/features/store/objects/DocumentQuickFilter.js +30 -0
  171. package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -0
  172. package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  173. package/lib/features/store/objects/DocumentSearchResults.js +17 -1
  174. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  175. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  176. package/lib/features/store/objects/components/ContentOverview.js +17 -74
  177. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  178. package/lib/features/store/objects/layout/DocumentTableColumn.d.ts +7 -1
  179. package/lib/features/store/objects/layout/DocumentTableColumn.d.ts.map +1 -1
  180. package/lib/features/store/objects/layout/DocumentTableColumn.js +27 -3
  181. package/lib/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
  182. package/lib/features/store/objects/layout/documentLayout.js +1 -1
  183. package/lib/features/store/objects/layout/renderers.d.ts +2 -1
  184. package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
  185. package/lib/features/store/objects/layout/renderers.js +27 -20
  186. package/lib/features/store/objects/layout/renderers.js.map +1 -1
  187. package/lib/features/store/types/ContentObjectTypesSearch.d.ts.map +1 -1
  188. package/lib/features/store/types/ContentObjectTypesSearch.js +4 -1
  189. package/lib/features/store/types/ContentObjectTypesSearch.js.map +1 -1
  190. package/lib/features/store/types/ContentObjectTypesTable.d.ts +2 -1
  191. package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
  192. package/lib/features/store/types/ContentObjectTypesTable.js +8 -3
  193. package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
  194. package/lib/i18n/instance.d.ts.map +1 -1
  195. package/lib/i18n/instance.js +1 -0
  196. package/lib/i18n/instance.js.map +1 -1
  197. package/lib/i18n/locales/ar.json +72 -45
  198. package/lib/i18n/locales/de.json +65 -34
  199. package/lib/i18n/locales/en.json +63 -47
  200. package/lib/i18n/locales/es.json +65 -35
  201. package/lib/i18n/locales/fr.json +65 -35
  202. package/lib/i18n/locales/it.json +72 -42
  203. package/lib/i18n/locales/ja.json +72 -41
  204. package/lib/i18n/locales/ko.json +72 -41
  205. package/lib/i18n/locales/pt.json +72 -42
  206. package/lib/i18n/locales/ru.json +72 -43
  207. package/lib/i18n/locales/tr.json +72 -41
  208. package/lib/i18n/locales/zh-TW.json +72 -41
  209. package/lib/i18n/locales/zh.json +72 -41
  210. package/lib/session/UserSession.d.ts +0 -6
  211. package/lib/session/UserSession.d.ts.map +1 -1
  212. package/lib/session/UserSession.js +0 -15
  213. package/lib/session/UserSession.js.map +1 -1
  214. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  215. package/lib/session/UserSessionProvider.js +39 -98
  216. package/lib/session/UserSessionProvider.js.map +1 -1
  217. package/lib/session/auth/composable.d.ts.map +1 -1
  218. package/lib/session/auth/composable.js +3 -33
  219. package/lib/session/auth/composable.js.map +1 -1
  220. package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
  221. package/lib/shell/login/SignInPrimitives.js +3 -2
  222. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  223. package/lib/vertesia-ui-core.js +1 -1
  224. package/lib/vertesia-ui-core.js.map +1 -1
  225. package/lib/vertesia-ui-env.js +1 -1
  226. package/lib/vertesia-ui-env.js.map +1 -1
  227. package/lib/vertesia-ui-features.js +1 -1
  228. package/lib/vertesia-ui-features.js.map +1 -1
  229. package/lib/vertesia-ui-i18n.js +1 -1
  230. package/lib/vertesia-ui-i18n.js.map +1 -1
  231. package/lib/vertesia-ui-session.js +1 -1
  232. package/lib/vertesia-ui-session.js.map +1 -1
  233. package/lib/vertesia-ui-shell.js +1 -1
  234. package/lib/vertesia-ui-shell.js.map +1 -1
  235. package/lib/vertesia-ui-widgets.js +1 -1
  236. package/lib/vertesia-ui-widgets.js.map +1 -1
  237. package/lib/widgets/schema-editor/editor/Editable.js +1 -1
  238. package/lib/widgets/schema-editor/editor/Editable.js.map +1 -1
  239. package/llms.txt +70 -70
  240. package/package.json +35 -32
  241. package/src/core/components/shadcn/dropdown.tsx +2 -0
  242. package/src/core/components/shadcn/filters/filterBar.tsx +9 -2
  243. package/src/core/components/shadcn/modal/ConfirmModal.tsx +65 -3
  244. package/src/core/components/shadcn/modal/dialog.tsx +1 -1
  245. package/src/core/components/shadcn/popover.tsx +1 -0
  246. package/src/core/components/shadcn/switch.tsx +4 -4
  247. package/src/core/components/shadcn/tabs.tsx +1 -1
  248. package/src/core/components/shadcn/tooltip.tsx +1 -0
  249. package/src/env/index.ts +0 -24
  250. package/src/features/agent/PayloadBuilder.tsx +18 -0
  251. package/src/features/agent/chat/AgentApprovalModeSelector.tsx +130 -0
  252. package/src/features/agent/chat/AgentChatFixtureReplay.test.tsx +22 -2
  253. package/src/features/agent/chat/AgentChatFixtureReplay.tsx +33 -27
  254. package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +122 -0
  255. package/src/features/agent/chat/AgentRequestInputOverlay.tsx +91 -17
  256. package/src/features/agent/chat/AgentRightPanel.tsx +238 -50
  257. package/src/features/agent/chat/AnimatedThinkingDots.tsx +1 -1
  258. package/src/features/agent/chat/ArtifactsTab.tsx +21 -155
  259. package/src/features/agent/chat/AskUserWidget.tsx +6 -2
  260. package/src/features/agent/chat/ModernAgentConversation.test.tsx +1157 -47
  261. package/src/features/agent/chat/ModernAgentConversation.tsx +703 -136
  262. package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +74 -0
  263. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +1420 -126
  264. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +934 -111
  265. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +31 -40
  266. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +28 -28
  267. package/src/features/agent/chat/ModernAgentOutput/MessageDeliveryStatus.tsx +83 -0
  268. package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +38 -2
  269. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +121 -98
  270. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +7 -1
  271. package/src/features/agent/chat/ModernAgentOutput/SlideInPanel.tsx +3 -3
  272. package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +1 -1
  273. package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +82 -2
  274. package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +2 -2
  275. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +216 -0
  276. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +149 -0
  277. package/src/features/agent/chat/ModernAgentOutput/utils.ts +103 -2
  278. package/src/features/agent/chat/clipboardFiles.ts +33 -0
  279. package/src/features/agent/chat/hooks/useAgentStream.test.tsx +355 -4
  280. package/src/features/agent/chat/hooks/useAgentStream.ts +270 -43
  281. package/src/features/agent/chat/hooks/useArtifacts.ts +11 -44
  282. package/src/features/agent/chat/index.ts +10 -1
  283. package/src/features/agent/chat/workstreams.ts +42 -0
  284. package/src/features/facets/AgentRunnerFacetsNav.tsx +23 -3
  285. package/src/features/facets/CollectionsFacetsNav.tsx +30 -5
  286. package/src/features/facets/PromptsFacetsNav.tsx +30 -5
  287. package/src/features/facets/RunsFacetsNav.tsx +32 -5
  288. package/src/features/index.ts +0 -1
  289. package/src/features/oauth/McpConnectionsButton.test.tsx +248 -0
  290. package/src/features/oauth/McpConnectionsButton.tsx +269 -0
  291. package/src/features/oauth/McpConnectionsDialog.tsx +142 -0
  292. package/src/features/oauth/RemoteMcpConnectionButton.tsx +37 -14
  293. package/src/features/oauth/index.ts +3 -0
  294. package/src/features/oauth/useMcpConnections.test.ts +94 -0
  295. package/src/features/oauth/useMcpConnections.ts +210 -0
  296. package/src/features/permissions/UserPermissionsProvider.tsx +41 -59
  297. package/src/features/store/objects/DocumentPreviewPanel.tsx +4 -2
  298. package/src/features/store/objects/DocumentQuickFilter.tsx +72 -0
  299. package/src/features/store/objects/DocumentSearchResults.tsx +30 -11
  300. package/src/features/store/objects/components/ContentOverview.tsx +30 -99
  301. package/src/features/store/objects/layout/DocumentTableColumn.tsx +29 -4
  302. package/src/features/store/objects/layout/documentLayout.tsx +1 -1
  303. package/src/features/store/objects/layout/renderers.tsx +80 -20
  304. package/src/features/store/types/ContentObjectTypesSearch.tsx +7 -1
  305. package/src/features/store/types/ContentObjectTypesTable.tsx +34 -4
  306. package/src/i18n/instance.ts +1 -0
  307. package/src/i18n/locales/ar.json +72 -45
  308. package/src/i18n/locales/de.json +65 -34
  309. package/src/i18n/locales/en.json +63 -47
  310. package/src/i18n/locales/es.json +65 -35
  311. package/src/i18n/locales/fr.json +65 -35
  312. package/src/i18n/locales/it.json +72 -42
  313. package/src/i18n/locales/ja.json +72 -41
  314. package/src/i18n/locales/ko.json +72 -41
  315. package/src/i18n/locales/pt.json +72 -42
  316. package/src/i18n/locales/ru.json +72 -43
  317. package/src/i18n/locales/tr.json +72 -41
  318. package/src/i18n/locales/zh-TW.json +72 -41
  319. package/src/i18n/locales/zh.json +72 -41
  320. package/src/i18n/rtl.test.ts +57 -1
  321. package/src/session/UserSession.ts +0 -16
  322. package/src/session/UserSessionProvider.tsx +51 -123
  323. package/src/session/auth/composable.ts +3 -34
  324. package/src/shell/login/SignInPrimitives.tsx +3 -2
  325. package/src/widgets/schema-editor/editor/Editable.tsx +1 -1
  326. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts +0 -73
  327. package/lib/features/document-viewer/UniversalDocumentViewer.d.ts.map +0 -1
  328. package/lib/features/document-viewer/UniversalDocumentViewer.js +0 -415
  329. package/lib/features/document-viewer/UniversalDocumentViewer.js.map +0 -1
  330. package/lib/features/document-viewer/index.d.ts +0 -2
  331. package/lib/features/document-viewer/index.d.ts.map +0 -1
  332. package/lib/features/document-viewer/index.js +0 -2
  333. package/lib/features/document-viewer/index.js.map +0 -1
  334. package/src/features/document-viewer/UniversalDocumentViewer.test.tsx +0 -123
  335. package/src/features/document-viewer/UniversalDocumentViewer.tsx +0 -746
  336. package/src/features/document-viewer/index.ts +0 -1
  337. package/src/session/auth/composable.test.ts +0 -79
@@ -100,6 +100,70 @@ describe('AllMessagesMixed summary view', () => {
100
100
  vi.useRealTimers();
101
101
  });
102
102
 
103
+ it('renders delivery status on user bubbles in summary view', () => {
104
+ renderSummary([
105
+ makeMessage({
106
+ timestamp: 1_000,
107
+ type: AgentMessageType.QUESTION,
108
+ message: 'Find Japan news.',
109
+ details: {
110
+ _deliveryStatus: 'consumed',
111
+ ack: 'message-1',
112
+ },
113
+ }),
114
+ ]);
115
+
116
+ expect(screen.getByLabelText('Message consumed')).not.toBeNull();
117
+ });
118
+
119
+ it('renders delivery status on user messages in stacked view', () => {
120
+ renderStacked([
121
+ makeMessage({
122
+ timestamp: 1_000,
123
+ type: AgentMessageType.QUESTION,
124
+ message: 'Find Japan news.',
125
+ details: {
126
+ _deliveryStatus: 'sending',
127
+ _messageId: 'message-1',
128
+ },
129
+ }),
130
+ ]);
131
+
132
+ expect(screen.getByLabelText('Sending message')).not.toBeNull();
133
+ });
134
+
135
+ it('renders an acked stop marker as a right-aligned consumed status row', () => {
136
+ renderSummary(
137
+ [
138
+ makeMessage({
139
+ timestamp: 2_000,
140
+ type: AgentMessageType.THOUGHT,
141
+ message: 'Searching',
142
+ details: {
143
+ tool: 'web_search',
144
+ tool_status: 'running',
145
+ tool_run_id: 'tool-1',
146
+ },
147
+ }),
148
+ makeMessage({
149
+ timestamp: 77_000,
150
+ type: AgentMessageType.IDLE,
151
+ message: 'Stopped. Waiting for your command...',
152
+ details: {
153
+ ack: 'stop-1',
154
+ status_reason: 'user_stopped',
155
+ },
156
+ }),
157
+ ],
158
+ true,
159
+ );
160
+
161
+ expect(screen.getByTestId('summary-stopped-message')).not.toBeNull();
162
+ expect(screen.getByText('You stopped after 1m 15s')).not.toBeNull();
163
+ expect(screen.getByLabelText('Message consumed')).not.toBeNull();
164
+ expect(screen.queryByText('Stopped. Waiting for your command...')).toBeNull();
165
+ });
166
+
103
167
  it('renders completed tool activity as a collapsed Worked row that expands to tool details', () => {
104
168
  renderSummary(
105
169
  [
@@ -138,16 +202,111 @@ describe('AllMessagesMixed summary view', () => {
138
202
  fireEvent.click(workedRow);
139
203
 
140
204
  expect(workedRow.getAttribute('aria-expanded')).toBe('true');
141
- expect(screen.getByText('Search')).not.toBeNull();
205
+ expect(screen.queryByText('Search')).toBeNull();
142
206
  expect(screen.getByText('Japan news')).not.toBeNull();
143
207
 
144
- const toolRow = screen.getByRole('button', { name: /Search\s*Japan news/ });
208
+ const toolRow = screen.getByRole('button', { name: /Japan news/ });
145
209
  expect(toolRow.getAttribute('aria-expanded')).toBe('false');
146
210
  fireEvent.click(toolRow);
147
211
 
212
+ expect(screen.getByText('Tool')).not.toBeNull();
213
+ expect(screen.getByText('web_search_serper')).not.toBeNull();
214
+ expect(screen.getByText('Time')).not.toBeNull();
148
215
  expect(screen.getByText('Found 5 results')).not.toBeNull();
149
216
  });
150
217
 
218
+ it('keeps same-iteration tool detail panels matched to their own tool identity', () => {
219
+ renderSummary(
220
+ [
221
+ makeMessage({
222
+ timestamp: 1_000,
223
+ type: AgentMessageType.QUESTION,
224
+ message: 'Launch France and Japan news workstreams.',
225
+ }),
226
+ makeMessage({
227
+ timestamp: 2_000,
228
+ message:
229
+ 'Updating the project plan to mark both workstream launches as completed and the monitoring phase as in-progress...',
230
+ details: {
231
+ event_class: 'activity',
232
+ tool: 'update_plan',
233
+ tool_run_id: 'update_plan',
234
+ tool_use_id: 'update_plan',
235
+ tool_iteration: 7,
236
+ tool_status: 'running',
237
+ tool_event: 'started',
238
+ activity_group_id: 'activity-7',
239
+ message_to_human:
240
+ 'Updating the project plan to mark both workstream launches as completed and the monitoring phase as in-progress...',
241
+ },
242
+ }),
243
+ makeMessage({
244
+ timestamp: 2_500,
245
+ message: 'Launching the Japan news headline gathering workstream...',
246
+ details: {
247
+ event_class: 'activity',
248
+ tool: 'launch_workstream',
249
+ tool_run_id: 'launch_workstream',
250
+ tool_use_id: 'launch_workstream',
251
+ tool_iteration: 7,
252
+ tool_status: 'running',
253
+ tool_event: 'started',
254
+ activity_group_id: 'activity-7',
255
+ message_to_human: 'Launching the Japan news headline gathering workstream...',
256
+ },
257
+ }),
258
+ makeMessage({
259
+ timestamp: 3_000,
260
+ type: AgentMessageType.UPDATE,
261
+ message: 'Updating 3 tasks of our plan.',
262
+ details: {
263
+ updates: [
264
+ { task_id: 1, status: 'completed' },
265
+ { task_id: 2, status: 'completed' },
266
+ { task_id: 3, status: 'in_progress' },
267
+ ],
268
+ },
269
+ }),
270
+ makeMessage({
271
+ timestamp: 3_001,
272
+ type: AgentMessageType.PLAN,
273
+ message:
274
+ 'Both news workstreams (France and Japan) have been successfully launched. We are now entering the monitoring phase.',
275
+ details: {
276
+ plan: [
277
+ { id: 1, status: 'completed', goal: 'Launch France workstream' },
278
+ { id: 2, status: 'completed', goal: 'Launch Japan workstream' },
279
+ { id: 3, status: 'in_progress', goal: 'Monitor both workstreams' },
280
+ ],
281
+ },
282
+ }),
283
+ makeMessage({
284
+ timestamp: 4_000,
285
+ type: AgentMessageType.ANSWER,
286
+ message: 'Done.',
287
+ }),
288
+ ],
289
+ true,
290
+ );
291
+
292
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for\s*2s/ }));
293
+
294
+ const updatePlanRow = screen.getByRole('button', { name: /Updating the project plan/ });
295
+ expect(screen.queryByRole('button', { name: /Updating 3 tasks/ })).toBeNull();
296
+ expect(screen.queryByRole('button', { name: /Both news workstreams/ })).toBeNull();
297
+
298
+ fireEvent.click(updatePlanRow);
299
+
300
+ expect(screen.getByText('update_plan')).not.toBeNull();
301
+ expect(screen.queryByText('launch_workstream')).toBeNull();
302
+ expect(screen.getByText(/"updates"/)).not.toBeNull();
303
+
304
+ const launchWorkstreamRow = screen.getByRole('button', { name: /Launching the Japan news/ });
305
+ fireEvent.click(launchWorkstreamRow);
306
+
307
+ expect(screen.getByText('launch_workstream')).not.toBeNull();
308
+ });
309
+
151
310
  it('renders active tool activity as an expanded Working row', () => {
152
311
  renderSummary([
153
312
  makeMessage({
@@ -169,11 +328,11 @@ describe('AllMessagesMixed summary view', () => {
169
328
 
170
329
  const workingRow = screen.getByRole('button', { name: /Working\s*for\s*1s/ });
171
330
  expect(workingRow.getAttribute('aria-expanded')).toBe('true');
172
- expect(screen.getByText('Bash')).not.toBeNull();
331
+ expect(screen.queryByText('Bash')).toBeNull();
173
332
  expect(screen.getByText('Running build')).not.toBeNull();
174
333
  expect(screen.queryByText('$ pnpm run build')).toBeNull();
175
334
 
176
- const toolRow = screen.getByRole('button', { name: /Bash\s*Running build/ });
335
+ const toolRow = screen.getByRole('button', { name: /Running build/ });
177
336
  fireEvent.click(toolRow);
178
337
 
179
338
  expect(screen.queryByText('Shell')).toBeNull();
@@ -181,6 +340,164 @@ describe('AllMessagesMixed summary view', () => {
181
340
  expect(screen.queryByText('Running')).toBeNull();
182
341
  });
183
342
 
343
+ it('keeps a pending tool approval prompt inside the active work row', () => {
344
+ const onSendMessage = vi.fn();
345
+
346
+ renderSummary(
347
+ [
348
+ makeMessage({
349
+ timestamp: Date.now() - 4_000,
350
+ type: AgentMessageType.QUESTION,
351
+ message: 'Create a news report.',
352
+ }),
353
+ makeMessage({
354
+ timestamp: Date.now() - 3_000,
355
+ message: 'Creating document from artifact...',
356
+ details: {
357
+ event_class: 'activity',
358
+ tool: 'create_document',
359
+ tool_run_id: 'create_document',
360
+ tool_use_id: 'create_document',
361
+ tool_status: 'running',
362
+ tool_event: 'started',
363
+ activity_group_id: 'activity-approval',
364
+ message_to_human: 'Creating document from artifact...',
365
+ },
366
+ }),
367
+ makeMessage({
368
+ timestamp: Date.now() - 1_000,
369
+ type: AgentMessageType.REQUEST_INPUT,
370
+ message: 'Approve Create Document: name News Headlines Today?',
371
+ details: {
372
+ tool_approval: {
373
+ approval_key: 'create_document:name:News Headlines Today',
374
+ tool_name: 'create_document',
375
+ tool_title: 'Create Document',
376
+ target: 'name:News Headlines Today',
377
+ },
378
+ ux: {
379
+ options: [
380
+ { id: 'allow_once', label: 'Allow once' },
381
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
382
+ { id: 'deny', label: 'Deny' },
383
+ ],
384
+ },
385
+ },
386
+ }),
387
+ ],
388
+ false,
389
+ new Map(),
390
+ { onSendMessage },
391
+ );
392
+
393
+ expect(screen.queryByRole('button', { name: /Worked\s*for/ })).toBeNull();
394
+ const workingRow = screen.getByRole('button', { name: /Working\s*for/ });
395
+ expect(workingRow.getAttribute('aria-expanded')).toBe('true');
396
+ expect(screen.getByText('Creating document from artifact...')).not.toBeNull();
397
+ expect(screen.getByText('Approve Create Document: News Headlines Today?')).not.toBeNull();
398
+ expect(screen.queryByText('Approve Create Document: name News Headlines Today?')).toBeNull();
399
+
400
+ fireEvent.click(screen.getByRole('button', { name: /Allow once/ }));
401
+
402
+ expect(onSendMessage).toHaveBeenCalledWith('allow_once');
403
+ });
404
+
405
+ it('keeps an approved tool approval continuation in the same active work row', () => {
406
+ renderSummary(
407
+ [
408
+ makeMessage({
409
+ timestamp: 1_000,
410
+ type: AgentMessageType.QUESTION,
411
+ message: 'Create a news report.',
412
+ }),
413
+ makeMessage({
414
+ timestamp: 2_000,
415
+ message: 'Creating the permanent news report document in the project repository...',
416
+ details: {
417
+ event_class: 'activity',
418
+ tool: 'create_document',
419
+ tool_run_id: 'create_document',
420
+ tool_use_id: 'create_document',
421
+ tool_status: 'running',
422
+ tool_event: 'started',
423
+ activity_group_id: 'activity-approval',
424
+ message_to_human: 'Creating the permanent news report document in the project repository...',
425
+ },
426
+ }),
427
+ makeMessage({
428
+ timestamp: 3_000,
429
+ type: AgentMessageType.REQUEST_INPUT,
430
+ message: 'Approve Create Document: Japan Daily News Report - June 22, 2026?',
431
+ details: {
432
+ tool_approval: {
433
+ approval_key: 'create_document:name:Japan Daily News Report - June 22, 2026',
434
+ tool_name: 'create_document',
435
+ tool_title: 'Create Document',
436
+ target: 'name:Japan Daily News Report - June 22, 2026',
437
+ },
438
+ ux: {
439
+ options: [
440
+ { id: 'allow_once', label: 'Allow once' },
441
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
442
+ { id: 'deny', label: 'Deny' },
443
+ ],
444
+ },
445
+ },
446
+ }),
447
+ makeMessage({
448
+ timestamp: 4_000,
449
+ type: AgentMessageType.QUESTION,
450
+ message: 'allow_for_run',
451
+ }),
452
+ ],
453
+ false,
454
+ );
455
+
456
+ expect(screen.queryByRole('button', { name: /Worked\s*for/ })).toBeNull();
457
+ expect(screen.getAllByRole('button', { name: /Working\s*for/ })).toHaveLength(1);
458
+ expect(
459
+ screen.getByText('Creating the permanent news report document in the project repository...'),
460
+ ).not.toBeNull();
461
+ expect(screen.queryByText('Approve Create Document: Japan Daily News Report - June 22, 2026?')).toBeNull();
462
+ expect(screen.queryByText('allow_for_run')).toBeNull();
463
+ });
464
+
465
+ it('expands tool rows that only have metadata', () => {
466
+ renderSummary(
467
+ [
468
+ makeMessage({
469
+ timestamp: 1_000,
470
+ type: AgentMessageType.QUESTION,
471
+ message: 'Warm the cache.',
472
+ }),
473
+ makeMessage({
474
+ timestamp: 2_000,
475
+ message: 'Loading cache',
476
+ details: {
477
+ tool: 'cache_loader',
478
+ tool_status: 'completed',
479
+ tool_run_id: 'tool-cache',
480
+ },
481
+ }),
482
+ ],
483
+ true,
484
+ );
485
+
486
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
487
+
488
+ const toolRow = screen.getByRole('button', { name: /Loading cache/ });
489
+ expect(toolRow.getAttribute('aria-expanded')).toBe('false');
490
+ expect(screen.queryByText('cache_loader')).toBeNull();
491
+
492
+ fireEvent.click(toolRow);
493
+
494
+ expect(toolRow.getAttribute('aria-expanded')).toBe('true');
495
+ expect(screen.getByText('Tool')).not.toBeNull();
496
+ expect(screen.getByText('cache_loader')).not.toBeNull();
497
+ expect(screen.getByText('Time')).not.toBeNull();
498
+ expect(screen.queryByRole('button', { name: 'Copy tool details' })).toBeNull();
499
+ });
500
+
184
501
  it('renders workstream launch events as inline workstream rows', () => {
185
502
  renderSummary(
186
503
  [
@@ -205,6 +522,17 @@ describe('AllMessagesMixed summary view', () => {
205
522
  child_workflow_run_id: 'run-qa-tasks',
206
523
  },
207
524
  }),
525
+ makeMessage({
526
+ timestamp: 3_000,
527
+ type: AgentMessageType.ANSWER,
528
+ message: 'Main agent response.',
529
+ }),
530
+ makeMessage({
531
+ timestamp: 4_000,
532
+ type: AgentMessageType.ANSWER,
533
+ message: 'Workstream-only result.',
534
+ workstream_id: 'qa_tasks',
535
+ }),
208
536
  ],
209
537
  true,
210
538
  );
@@ -212,87 +540,188 @@ describe('AllMessagesMixed summary view', () => {
212
540
  expect(screen.getByText('Workstreams')).not.toBeNull();
213
541
  expect(screen.getByText('QA Tasks')).not.toBeNull();
214
542
  expect(screen.getByText('Browser Agent')).not.toBeNull();
543
+ expect(screen.queryByText('Workstream-only result.')).toBeNull();
544
+
545
+ fireEvent.click(screen.getByRole('button', { name: /QA Tasks/ }));
546
+
547
+ expect(screen.getByRole('button', { name: 'Back to main agent' })).not.toBeNull();
548
+ expect(screen.getByText('Workstream-only result.')).not.toBeNull();
549
+ expect(screen.queryByText('Main agent response.')).toBeNull();
550
+ expect(screen.queryByText('Workstreams')).toBeNull();
551
+
552
+ fireEvent.click(screen.getByRole('button', { name: 'Back to main agent' }));
553
+
554
+ expect(screen.getByText('Main agent response.')).not.toBeNull();
215
555
  });
216
556
 
217
- it('suppresses JSON-only child workstream results in summary view', () => {
557
+ it('renders first child workflow activity as a workstream row when the launch event is missing', () => {
218
558
  renderSummary(
219
559
  [
220
560
  makeMessage({
221
561
  timestamp: 1_000,
222
562
  type: AgentMessageType.QUESTION,
223
- message: 'Generate a picture.',
563
+ message: 'Check the app.',
224
564
  }),
225
565
  makeMessage({
226
566
  timestamp: 2_000,
227
- type: AgentMessageType.THOUGHT,
228
- message: 'I am generating the image with a specialist agent.',
229
- details: {
230
- streamed: true,
231
- },
232
- }),
233
- makeMessage({
234
- timestamp: 3_000,
235
567
  type: AgentMessageType.UPDATE,
236
- message: 'Workstream "ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6" launched',
237
- workstream_id: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
568
+ message: 'Browser agent started.',
569
+ workstream_id: 'legacy_browser',
238
570
  details: {
239
571
  event_class: 'activity',
240
- workstream_event: 'launched',
241
- launch_id: 'launch-1',
242
- workstream_id: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
243
- kind: 'agent',
244
- interaction: 'ImageGeneratorAgent',
572
+ workstream_id: 'legacy_browser',
573
+ interaction: 'sys:BrowserAgent',
574
+ child_workflow_id: 'workstream:legacy_browser',
575
+ child_workflow_run_id: 'run-legacy-browser',
245
576
  },
246
577
  }),
247
578
  makeMessage({
248
- timestamp: 4_000,
579
+ timestamp: 3_000,
249
580
  type: AgentMessageType.ANSWER,
250
- message: '{"generated_images":["store:object-1"]}',
251
- workstream_id: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
252
- details: {
253
- event_class: 'user_content',
254
- streamed: true,
255
- },
581
+ message: 'Main agent response.',
256
582
  }),
257
583
  makeMessage({
258
- timestamp: 5_000,
584
+ timestamp: 4_000,
259
585
  type: AgentMessageType.ANSWER,
260
- message: 'I saved the generated image as a content object.',
261
- workstream_id: 'main',
586
+ message: 'Legacy workstream-only result.',
587
+ workstream_id: 'legacy_browser',
262
588
  }),
263
589
  ],
264
590
  true,
265
- new Map([
266
- [
267
- 'stream-json',
268
- {
269
- text: '{"generated_images":["store:object-2"]}',
270
- workstreamId: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
271
- isComplete: true,
272
- startTimestamp: 4_500,
273
- },
274
- ],
275
- ]),
276
591
  );
277
592
 
278
- expect(screen.getByText('Generate a picture.')).not.toBeNull();
279
- expect(screen.getByText('Image Generator Agent')).not.toBeNull();
280
- expect(screen.getByText('I saved the generated image as a content object.')).not.toBeNull();
281
- expect(screen.queryByText(/generated_images/)).toBeNull();
282
- expect(screen.queryByText(/store:object/)).toBeNull();
593
+ expect(screen.getByText('Workstreams')).not.toBeNull();
594
+ expect(screen.getByText('Legacy Browser')).not.toBeNull();
595
+ expect(screen.getByText('Browser Agent')).not.toBeNull();
596
+ expect(screen.queryByText('Legacy workstream-only result.')).toBeNull();
597
+
598
+ fireEvent.click(screen.getByRole('button', { name: /Legacy Browser/ }));
599
+
600
+ expect(screen.getByRole('button', { name: 'Back to main agent' })).not.toBeNull();
601
+ expect(screen.getByText('Legacy workstream-only result.')).not.toBeNull();
602
+ expect(screen.queryByText('Main agent response.')).toBeNull();
603
+ expect(screen.queryByText('Workstreams')).toBeNull();
283
604
  });
284
605
 
285
- it('renders question attachment markdown as a store object link in summary view', () => {
606
+ it('does not render a failed pre-launch workstream activity as a clickable workstream row', () => {
286
607
  renderSummary(
287
608
  [
288
609
  makeMessage({
289
610
  timestamp: 1_000,
290
611
  type: AgentMessageType.QUESTION,
291
- message: [
292
- 'what is in this image?',
293
- '',
294
- 'Attachments:',
295
- '[tokyo-tower_1 (1).jpg](/store/objects/6a17fc9544c9629943624589)',
612
+ message: 'Create a bookmark.',
613
+ }),
614
+ makeMessage({
615
+ timestamp: 2_000,
616
+ type: AgentMessageType.UPDATE,
617
+ message: 'Provisioning browser sandbox for "Create Bookmark"...',
618
+ workstream_id: 'create_bookmark',
619
+ details: {
620
+ event_class: 'activity',
621
+ workstream_id: 'create_bookmark',
622
+ },
623
+ }),
624
+ makeMessage({
625
+ timestamp: 3_000,
626
+ type: AgentMessageType.ERROR,
627
+ message: 'Failed to provision browser sandbox: Request failed with status code 502',
628
+ workstream_id: 'create_bookmark',
629
+ details: {
630
+ event_class: 'activity',
631
+ workstream_id: 'create_bookmark',
632
+ },
633
+ }),
634
+ ],
635
+ true,
636
+ );
637
+
638
+ expect(screen.queryByText('Workstreams')).toBeNull();
639
+ expect(screen.queryByText('Create Bookmark')).toBeNull();
640
+ expect(screen.queryByText('Error')).toBeNull();
641
+ expect(screen.queryByRole('button', { name: /Work needs attention/ })).toBeNull();
642
+ expect(screen.getByRole('button', { name: /Working/ })).not.toBeNull();
643
+ expect(screen.getByText(/Failed to provision browser sandbox/)).not.toBeNull();
644
+ });
645
+
646
+ it('suppresses JSON-only child workstream results in summary view', () => {
647
+ renderSummary(
648
+ [
649
+ makeMessage({
650
+ timestamp: 1_000,
651
+ type: AgentMessageType.QUESTION,
652
+ message: 'Generate a picture.',
653
+ }),
654
+ makeMessage({
655
+ timestamp: 2_000,
656
+ type: AgentMessageType.THOUGHT,
657
+ message: 'I am generating the image with a specialist agent.',
658
+ details: {
659
+ streamed: true,
660
+ },
661
+ }),
662
+ makeMessage({
663
+ timestamp: 3_000,
664
+ type: AgentMessageType.UPDATE,
665
+ message: 'Workstream "ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6" launched',
666
+ workstream_id: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
667
+ details: {
668
+ event_class: 'activity',
669
+ workstream_event: 'launched',
670
+ launch_id: 'launch-1',
671
+ workstream_id: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
672
+ kind: 'agent',
673
+ interaction: 'ImageGeneratorAgent',
674
+ },
675
+ }),
676
+ makeMessage({
677
+ timestamp: 4_000,
678
+ type: AgentMessageType.ANSWER,
679
+ message: '{"generated_images":["store:object-1"]}',
680
+ workstream_id: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
681
+ details: {
682
+ event_class: 'user_content',
683
+ streamed: true,
684
+ },
685
+ }),
686
+ makeMessage({
687
+ timestamp: 5_000,
688
+ type: AgentMessageType.ANSWER,
689
+ message: 'I saved the generated image as a content object.',
690
+ workstream_id: 'main',
691
+ }),
692
+ ],
693
+ true,
694
+ new Map([
695
+ [
696
+ 'stream-json',
697
+ {
698
+ text: '{"generated_images":["store:object-2"]}',
699
+ workstreamId: 'ImageGeneratorAgent-16b7f73a-8e8e-40b7-b891-cb47a78c38c6',
700
+ isComplete: true,
701
+ startTimestamp: 4_500,
702
+ },
703
+ ],
704
+ ]),
705
+ );
706
+
707
+ expect(screen.getByText('Generate a picture.')).not.toBeNull();
708
+ expect(screen.getByText('Image Generator Agent')).not.toBeNull();
709
+ expect(screen.getByText('I saved the generated image as a content object.')).not.toBeNull();
710
+ expect(screen.queryByText(/generated_images/)).toBeNull();
711
+ expect(screen.queryByText(/store:object/)).toBeNull();
712
+ });
713
+
714
+ it('renders question attachment markdown as a store object link in summary view', () => {
715
+ renderSummary(
716
+ [
717
+ makeMessage({
718
+ timestamp: 1_000,
719
+ type: AgentMessageType.QUESTION,
720
+ message: [
721
+ 'what is in this image?',
722
+ '',
723
+ 'Attachments:',
724
+ '[tokyo-tower_1 (1).jpg](/store/objects/6a17fc9544c9629943624589)',
296
725
  ].join('\n'),
297
726
  }),
298
727
  ],
@@ -429,16 +858,82 @@ describe('AllMessagesMixed summary view', () => {
429
858
  const workedRow = screen.getByRole('button', { name: /Worked\s*for\s*1s/ });
430
859
  fireEvent.click(workedRow);
431
860
 
432
- expect(screen.getByRole('button', { name: /Bash\s*Running production build preflight/ })).not.toBeNull();
861
+ expect(screen.getByRole('button', { name: /Running production build preflight/ })).not.toBeNull();
433
862
  expect(screen.queryByRole('button', { name: /\$ cd \/home\/daytona\/src/ })).toBeNull();
434
863
 
435
- fireEvent.click(screen.getByRole('button', { name: /Bash\s*Running production build preflight/ }));
864
+ fireEvent.click(screen.getByRole('button', { name: /Running production build preflight/ }));
436
865
 
437
866
  expect(screen.getByText('$ cd /home/daytona/src && pnpm run build completed successfully')).not.toBeNull();
438
867
  expect(screen.getByText('Build output')).not.toBeNull();
439
868
  expect(screen.queryByText('Success')).toBeNull();
440
869
  });
441
870
 
871
+ it('merges legacy plan update rows with the preceding update_plan tool row', () => {
872
+ renderSummary(
873
+ [
874
+ makeMessage({
875
+ timestamp: 1_000,
876
+ type: AgentMessageType.QUESTION,
877
+ message: 'What are the news headlines in France today?',
878
+ }),
879
+ makeMessage({
880
+ timestamp: 2_000,
881
+ message: "Updating the plan and performing a Google web search for today's headlines in France.",
882
+ details: {
883
+ event_class: 'activity',
884
+ tool: 'update_plan',
885
+ tool_run_id: 'update_plan',
886
+ tool_status: 'running',
887
+ tool_event: 'started',
888
+ activity_group_id: 'activity-4',
889
+ message_to_human:
890
+ "Updating the plan and performing a Google web search for today's headlines in France.",
891
+ },
892
+ }),
893
+ makeMessage({
894
+ timestamp: 3_000,
895
+ type: AgentMessageType.UPDATE,
896
+ message: 'Updating 2 tasks of our plan.',
897
+ details: {
898
+ updates: [
899
+ { task_id: 1, status: 'completed' },
900
+ { task_id: 2, status: 'in_progress' },
901
+ ],
902
+ },
903
+ }),
904
+ makeMessage({
905
+ timestamp: 4_000,
906
+ type: AgentMessageType.PLAN,
907
+ message:
908
+ 'Task 1 (Learn the web search skill) has been completed successfully. Now commencing Task 2.',
909
+ details: {
910
+ plan: [
911
+ { id: 1, goal: 'Learn the web search skill', status: 'completed' },
912
+ { id: 2, goal: "Search for today's headlines in France", status: 'in_progress' },
913
+ ],
914
+ },
915
+ }),
916
+ ],
917
+ true,
918
+ );
919
+
920
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
921
+
922
+ const planRow = screen.getByRole('button', {
923
+ name: /Updating the plan and performing a Google web search/,
924
+ });
925
+ expect(planRow).not.toBeNull();
926
+ expect(screen.queryByRole('button', { name: /Updating 2 tasks of our plan/ })).toBeNull();
927
+ expect(screen.queryByRole('button', { name: /Task 1 \(Learn the web search skill\)/ })).toBeNull();
928
+
929
+ fireEvent.click(planRow);
930
+
931
+ expect(screen.getByText('update_plan')).not.toBeNull();
932
+ expect(screen.getByText('Started')).not.toBeNull();
933
+ expect(screen.getByText('Ended')).not.toBeNull();
934
+ expect(screen.getByText('Duration')).not.toBeNull();
935
+ });
936
+
442
937
  it('copies expanded tool details without requiring the parent row click target', () => {
443
938
  const writeText = vi.fn().mockResolvedValue(undefined);
444
939
  Object.defineProperty(navigator, 'clipboard', {
@@ -454,105 +949,610 @@ describe('AllMessagesMixed summary view', () => {
454
949
  message: 'Find Japan news.',
455
950
  }),
456
951
  makeMessage({
457
- timestamp: 2_000,
458
- message: 'Searching for Japan news',
952
+ timestamp: 2_000,
953
+ message: 'Searching for Japan news',
954
+ details: {
955
+ tool: 'web_search_serper',
956
+ tool_status: 'completed',
957
+ tool_run_id: 'tool-1',
958
+ query: 'Japan news',
959
+ output: 'Found 5 results',
960
+ },
961
+ }),
962
+ ],
963
+ true,
964
+ );
965
+
966
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
967
+ fireEvent.click(screen.getByRole('button', { name: /Japan news/ }));
968
+ fireEvent.click(screen.getByRole('button', { name: 'Copy tool details' }));
969
+
970
+ expect(writeText).toHaveBeenCalledWith(expect.stringContaining('Tool: web_search_serper'));
971
+ expect(writeText).toHaveBeenCalledWith(expect.stringContaining('Found 5 results'));
972
+ });
973
+
974
+ it('does not expand tool error details by default', () => {
975
+ renderSummary(
976
+ [
977
+ makeMessage({
978
+ timestamp: 1_000,
979
+ type: AgentMessageType.QUESTION,
980
+ message: 'Publish the app.',
981
+ }),
982
+ makeMessage({
983
+ timestamp: 2_000,
984
+ message: 'Publishing app...',
985
+ details: {
986
+ activity_group_id: 'activity-10',
987
+ tool: 'app_publish',
988
+ tool_run_id: 'publish-wrapper',
989
+ tool_status: 'running',
990
+ },
991
+ }),
992
+ makeMessage({
993
+ timestamp: 3_000,
994
+ type: AgentMessageType.ERROR,
995
+ message: 'App publish blocked until preview validation passes',
996
+ details: {
997
+ activity_group_id: 'activity-10',
998
+ tool: 'app_publish',
999
+ tool_run_id: 'publish-progress',
1000
+ tool_status: 'error',
1001
+ },
1002
+ }),
1003
+ ],
1004
+ true,
1005
+ );
1006
+
1007
+ expect(screen.queryByRole('button', { name: /Work needs attention/ })).toBeNull();
1008
+ const workRow = screen.getByRole('button', { name: /Worked\s*for\s*1s/ });
1009
+ fireEvent.click(workRow);
1010
+
1011
+ const toolRow = screen.getByRole('button', { name: /Publishing app/ });
1012
+ expect(toolRow.getAttribute('aria-expanded')).toBe('false');
1013
+ expect(screen.queryByText('App publish blocked until preview validation passes')).toBeNull();
1014
+
1015
+ fireEvent.click(toolRow);
1016
+
1017
+ expect(screen.getByText('App publish blocked until preview validation passes')).not.toBeNull();
1018
+ });
1019
+
1020
+ it('marks denied tool approvals as error rows with expandable approval details', () => {
1021
+ renderSummary(
1022
+ [
1023
+ makeMessage({
1024
+ timestamp: 1_000,
1025
+ type: AgentMessageType.QUESTION,
1026
+ message: 'Create a document.',
1027
+ }),
1028
+ makeMessage({
1029
+ timestamp: 2_000,
1030
+ message: 'Writing the document to a temporary markdown file...',
1031
+ details: {
1032
+ event_class: 'activity',
1033
+ activity_group_id: 'activity-approval-1',
1034
+ tool: 'write_artifact',
1035
+ tool_run_id: 'write-1',
1036
+ tool_use_id: 'write-1',
1037
+ tool_status: 'running',
1038
+ tool_event: 'started',
1039
+ message_to_human: 'Writing the document to a temporary markdown file...',
1040
+ },
1041
+ }),
1042
+ makeMessage({
1043
+ timestamp: 3_000,
1044
+ message: 'User declined to use Write Artifact.',
1045
+ details: {
1046
+ event_class: 'activity',
1047
+ activity_group_id: 'activity-approval-1',
1048
+ tool: 'write_artifact',
1049
+ tool_run_id: 'write-1',
1050
+ tool_use_id: 'write-1',
1051
+ tool_status: 'error',
1052
+ tool_event: 'failed',
1053
+ approval_decision: 'denied',
1054
+ approval_request: {
1055
+ tool_name: 'write_artifact',
1056
+ tool_title: 'Write Artifact',
1057
+ target: 'name:quotes.md',
1058
+ approval_key: 'write_artifact:name:quotes.md',
1059
+ },
1060
+ input: {
1061
+ name: 'quotes.md',
1062
+ type: 'file',
1063
+ },
1064
+ observation: 'The user declined this tool action.',
1065
+ },
1066
+ }),
1067
+ ],
1068
+ true,
1069
+ );
1070
+
1071
+ expect(screen.queryByRole('button', { name: /Work needs attention\s*for/ })).toBeNull();
1072
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
1073
+
1074
+ expect(screen.queryByRole('button', { name: /User declined to use Write Artifact/ })).toBeNull();
1075
+ const deniedRow = screen.getByRole('button', { name: /Writing the document.*Declined by user/ });
1076
+ expect(deniedRow.getAttribute('aria-expanded')).toBe('false');
1077
+
1078
+ fireEvent.click(deniedRow);
1079
+
1080
+ expect(screen.queryByText('Decision')).toBeNull();
1081
+ expect(screen.queryByText('denied')).toBeNull();
1082
+ expect(screen.queryByText('Approval request')).toBeNull();
1083
+ expect(screen.getAllByText(/quotes\.md/).length).toBeGreaterThan(0);
1084
+ const deniedMessage = screen.getByText('The user declined this tool action.');
1085
+ expect(deniedMessage.className).toContain('text-destructive');
1086
+ });
1087
+
1088
+ it('does not split a denied approval into separate worked and attention rows', () => {
1089
+ renderSummary(
1090
+ [
1091
+ makeMessage({
1092
+ timestamp: 1_000,
1093
+ type: AgentMessageType.QUESTION,
1094
+ message: 'Create a document.',
1095
+ }),
1096
+ makeMessage({
1097
+ timestamp: 2_000,
1098
+ message: 'Writing the document to a temporary markdown file...',
1099
+ details: {
1100
+ event_class: 'activity',
1101
+ activity_group_id: 'activity-approval-2',
1102
+ tool: 'write_artifact',
1103
+ tool_run_id: 'write-2',
1104
+ tool_use_id: 'write-2',
1105
+ tool_status: 'running',
1106
+ tool_event: 'started',
1107
+ message_to_human: 'Writing the document to a temporary markdown file...',
1108
+ },
1109
+ }),
1110
+ makeMessage({
1111
+ timestamp: 3_000,
1112
+ type: AgentMessageType.REQUEST_INPUT,
1113
+ message: 'Approve Write Artifact: quotes.md?',
1114
+ details: {
1115
+ tool_approval: {
1116
+ tool_name: 'write_artifact',
1117
+ tool_title: 'Write Artifact',
1118
+ action_summary: 'Write Artifact: quotes.md',
1119
+ target: 'name:quotes.md',
1120
+ approval_key: 'write_artifact:name:quotes.md',
1121
+ input: {
1122
+ name: 'quotes.md',
1123
+ type: 'file',
1124
+ },
1125
+ },
1126
+ ux: {
1127
+ options: [
1128
+ { id: 'allow_once', label: 'Allow once' },
1129
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1130
+ { id: 'deny', label: 'Deny' },
1131
+ ],
1132
+ },
1133
+ },
1134
+ }),
1135
+ makeMessage({
1136
+ timestamp: 4_000,
1137
+ type: AgentMessageType.QUESTION,
1138
+ message: 'deny',
1139
+ }),
1140
+ makeMessage({
1141
+ timestamp: 5_000,
1142
+ message: 'User declined to use Write Artifact.',
1143
+ details: {
1144
+ event_class: 'activity',
1145
+ activity_group_id: 'activity-approval-2',
1146
+ tool: 'write_artifact',
1147
+ tool_run_id: 'write-2',
1148
+ tool_use_id: 'write-2',
1149
+ tool_status: 'error',
1150
+ tool_event: 'failed',
1151
+ approval_decision: 'denied',
1152
+ approval_request: {
1153
+ tool_name: 'write_artifact',
1154
+ tool_title: 'Write Artifact',
1155
+ target: 'name:quotes.md',
1156
+ approval_key: 'write_artifact:name:quotes.md',
1157
+ },
1158
+ input: {
1159
+ name: 'quotes.md',
1160
+ type: 'file',
1161
+ },
1162
+ observation: 'The user declined this tool action.',
1163
+ },
1164
+ }),
1165
+ ],
1166
+ true,
1167
+ );
1168
+
1169
+ expect(screen.queryByText('Approve Write Artifact: quotes.md?')).toBeNull();
1170
+ expect(screen.queryByText('deny')).toBeNull();
1171
+ expect(screen.queryByRole('button', { name: /Work needs attention\s*for/ })).toBeNull();
1172
+
1173
+ const workRows = screen.getAllByRole('button', { name: /Worked\s*for/ });
1174
+ expect(workRows).toHaveLength(1);
1175
+ fireEvent.click(workRows[0]);
1176
+
1177
+ expect(screen.queryByRole('button', { name: /User declined to use Write Artifact/ })).toBeNull();
1178
+ expect(screen.getByRole('button', { name: /Writing the document.*Declined by user/ })).not.toBeNull();
1179
+ });
1180
+
1181
+ it('renders a compact denied tool row for legacy approvals without lifecycle events', () => {
1182
+ renderSummary(
1183
+ [
1184
+ makeMessage({
1185
+ timestamp: 1_000,
1186
+ type: AgentMessageType.QUESTION,
1187
+ message: 'Create a document.',
1188
+ }),
1189
+ makeMessage({
1190
+ timestamp: 2_000,
1191
+ message: 'Writing the document to a temporary markdown file...',
1192
+ details: {
1193
+ event_class: 'activity',
1194
+ activity_group_id: 'activity-legacy-approval',
1195
+ tool: 'write_artifact',
1196
+ tool_run_id: 'write-legacy-1',
1197
+ tool_status: 'running',
1198
+ tool_event: 'started',
1199
+ },
1200
+ }),
1201
+ makeMessage({
1202
+ timestamp: 3_000,
1203
+ type: AgentMessageType.REQUEST_INPUT,
1204
+ message: 'Approve Write Artifact: quotes.md?',
1205
+ details: {
1206
+ tool_approval: {
1207
+ tool_name: 'write_artifact',
1208
+ tool_title: 'Write Artifact',
1209
+ action_summary: 'Write Artifact: quotes.md',
1210
+ target: 'name:quotes.md',
1211
+ approval_key: 'write_artifact:name:quotes.md',
1212
+ input: {
1213
+ name: 'quotes.md',
1214
+ type: 'file',
1215
+ },
1216
+ },
1217
+ ux: {
1218
+ options: [
1219
+ { id: 'allow_once', label: 'Allow once' },
1220
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1221
+ { id: 'deny', label: 'Deny' },
1222
+ ],
1223
+ },
1224
+ },
1225
+ }),
1226
+ makeMessage({
1227
+ timestamp: 4_000,
1228
+ type: AgentMessageType.QUESTION,
1229
+ message: 'deny',
1230
+ }),
1231
+ ],
1232
+ true,
1233
+ );
1234
+
1235
+ expect(screen.queryByText('Approve Write Artifact: quotes.md?')).toBeNull();
1236
+ expect(screen.queryByText('deny')).toBeNull();
1237
+
1238
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
1239
+ const deniedRow = screen.getByRole('button', { name: /Write Artifact.*Declined by user/ });
1240
+ fireEvent.click(deniedRow);
1241
+
1242
+ expect(screen.queryByText('Decision')).toBeNull();
1243
+ expect(screen.queryByText('denied')).toBeNull();
1244
+ expect(screen.queryByText('Approval request')).toBeNull();
1245
+ expect(screen.getAllByText(/quotes\.md/).length).toBeGreaterThan(0);
1246
+ });
1247
+
1248
+ it('renders pending ask options compactly in summary view', () => {
1249
+ renderSummary([
1250
+ makeMessage({
1251
+ timestamp: 1_000,
1252
+ type: AgentMessageType.REQUEST_INPUT,
1253
+ message: 'What is your favorite color?',
1254
+ details: {
1255
+ ux: {
1256
+ options: [
1257
+ { id: 'red', label: 'Red', description: 'The color of fire and passion' },
1258
+ { id: 'blue', label: 'Blue', description: 'The color of the sky and ocean' },
1259
+ ],
1260
+ },
1261
+ },
1262
+ }),
1263
+ ]);
1264
+
1265
+ expect(screen.getByText('What is your favorite color?')).not.toBeNull();
1266
+ expect(screen.getByRole('button', { name: /Blue\s*The color of the sky and ocean/ })).not.toBeNull();
1267
+ });
1268
+
1269
+ it('renders legacy field-prefixed tool approval prompts with a friendly target in summary view', () => {
1270
+ renderSummary([
1271
+ makeMessage({
1272
+ timestamp: 1_000,
1273
+ type: AgentMessageType.REQUEST_INPUT,
1274
+ message: 'Approve Create Document: name News Headlines Today?',
1275
+ details: {
1276
+ tool_approval: {
1277
+ approval_key: 'create_document:name:News Headlines Today',
1278
+ tool_name: 'create_document',
1279
+ tool_title: 'Create Document',
1280
+ target: 'name:News Headlines Today',
1281
+ },
1282
+ ux: {
1283
+ options: [
1284
+ { id: 'allow_once', label: 'Allow once' },
1285
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1286
+ { id: 'deny', label: 'Deny' },
1287
+ ],
1288
+ },
1289
+ },
1290
+ }),
1291
+ ]);
1292
+
1293
+ expect(screen.getByText('Approve Create Document: News Headlines Today?')).not.toBeNull();
1294
+ expect(screen.queryByText('Approve Create Document: name News Headlines Today?')).toBeNull();
1295
+ });
1296
+
1297
+ it('keeps only the ask question after the user answers in summary view', () => {
1298
+ renderSummary(
1299
+ [
1300
+ makeMessage({
1301
+ timestamp: 1_000,
1302
+ type: AgentMessageType.REQUEST_INPUT,
1303
+ message: 'What is your favorite color?',
1304
+ details: {
1305
+ ux: {
1306
+ options: [
1307
+ { id: 'red', label: 'Red', description: 'The color of fire and passion' },
1308
+ { id: 'blue', label: 'Blue', description: 'The color of the sky and ocean' },
1309
+ ],
1310
+ },
1311
+ },
1312
+ }),
1313
+ makeMessage({
1314
+ timestamp: 2_000,
1315
+ type: AgentMessageType.QUESTION,
1316
+ message: 'blue',
1317
+ }),
1318
+ ],
1319
+ true,
1320
+ );
1321
+
1322
+ expect(screen.getByText('What is your favorite color?')).not.toBeNull();
1323
+ expect(screen.getByText('blue')).not.toBeNull();
1324
+ expect(screen.queryByText('The color of the sky and ocean')).toBeNull();
1325
+ expect(screen.queryByRole('button', { name: /Blue/ })).toBeNull();
1326
+ });
1327
+
1328
+ it('hides denied tool approval prompts when the stream contains a denied tool event', () => {
1329
+ renderSummary(
1330
+ [
1331
+ makeMessage({
1332
+ timestamp: 1_000,
1333
+ type: AgentMessageType.REQUEST_INPUT,
1334
+ message: 'Approve Write Artifact for japan_news_2026_06_21.md?',
1335
+ details: {
1336
+ tool_approval: {
1337
+ approval_key: 'write_artifact:name:japan_news_2026_06_21.md',
1338
+ tool_name: 'write_artifact',
1339
+ tool_title: 'Write Artifact',
1340
+ target: 'name:japan_news_2026_06_21.md',
1341
+ input: {
1342
+ name: 'japan_news_2026_06_21.md',
1343
+ content_ref: {
1344
+ display_ref: 'artifact:tool-inputs/write_artifact/write_artifact.txt',
1345
+ },
1346
+ },
1347
+ },
1348
+ ux: {
1349
+ options: [
1350
+ { id: 'allow_once', label: 'Allow once' },
1351
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1352
+ { id: 'deny', label: 'Deny' },
1353
+ ],
1354
+ },
1355
+ },
1356
+ }),
1357
+ makeMessage({
1358
+ timestamp: 2_000,
1359
+ type: AgentMessageType.QUESTION,
1360
+ message: 'deny',
1361
+ }),
1362
+ makeMessage({
1363
+ timestamp: 3_000,
1364
+ type: AgentMessageType.THOUGHT,
1365
+ message: 'User declined to use Write Artifact.',
1366
+ details: {
1367
+ event_class: 'activity',
1368
+ tool: 'write_artifact',
1369
+ tool_run_id: 'tool-run-1',
1370
+ tool_use_id: 'tool-use-1',
1371
+ tool_status: 'error',
1372
+ tool_event: 'failed',
1373
+ activity_group_id: 'activity-1',
1374
+ observation: 'User declined to use Write Artifact.',
1375
+ approval_decision: 'denied',
1376
+ approval_request: {
1377
+ approval_key: 'write_artifact:name:japan_news_2026_06_21.md',
1378
+ tool_name: 'write_artifact',
1379
+ tool_title: 'Write Artifact',
1380
+ target: 'name:japan_news_2026_06_21.md',
1381
+ },
1382
+ input: {
1383
+ name: 'japan_news_2026_06_21.md',
1384
+ content_ref: {
1385
+ display_ref: 'artifact:tool-inputs/write_artifact/write_artifact.txt',
1386
+ },
1387
+ },
1388
+ },
1389
+ }),
1390
+ makeMessage({
1391
+ timestamp: 3_500,
1392
+ type: AgentMessageType.REQUEST_INPUT,
1393
+ message: 'Approve Create Document: Japan News Headlines?',
1394
+ details: {
1395
+ tool_approval: {
1396
+ approval_key: 'create_document:name:Japan News Headlines',
1397
+ tool_name: 'create_document',
1398
+ tool_title: 'Create Document',
1399
+ target: 'name:Japan News Headlines',
1400
+ input: {
1401
+ name: 'Japan News Headlines',
1402
+ source: 'artifact:files/japan_news_2026_06_21.md',
1403
+ },
1404
+ },
1405
+ ux: {
1406
+ options: [
1407
+ { id: 'allow_once', label: 'Allow once' },
1408
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1409
+ { id: 'deny', label: 'Deny' },
1410
+ ],
1411
+ },
1412
+ },
1413
+ }),
1414
+ makeMessage({
1415
+ timestamp: 4_000,
1416
+ type: AgentMessageType.THOUGHT,
1417
+ message: 'Cancelled Create Document after denial.',
459
1418
  details: {
460
- tool: 'web_search_serper',
461
- tool_status: 'completed',
462
- tool_run_id: 'tool-1',
463
- query: 'Japan news',
464
- output: 'Found 5 results',
1419
+ event_class: 'activity',
1420
+ tool: 'create_document',
1421
+ tool_run_id: 'tool-run-2',
1422
+ tool_use_id: 'tool-use-2',
1423
+ tool_status: 'error',
1424
+ tool_event: 'failed',
1425
+ activity_group_id: 'activity-1',
1426
+ observation: 'Tool execution was cancelled because another tool action was denied.',
1427
+ approval_decision: 'cancelled_after_denial',
1428
+ approval_request: {
1429
+ approval_key: 'create_document:name:Japan News Headlines',
1430
+ tool_name: 'create_document',
1431
+ tool_title: 'Create Document',
1432
+ target: 'name:Japan News Headlines',
1433
+ },
1434
+ input: {
1435
+ name: 'Japan News Headlines',
1436
+ source: 'artifact:files/japan_news_2026_06_21.md',
1437
+ },
465
1438
  },
466
1439
  }),
467
1440
  ],
468
1441
  true,
469
1442
  );
470
1443
 
471
- fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
472
- fireEvent.click(screen.getByRole('button', { name: /Search\s*Japan news/ }));
473
- fireEvent.click(screen.getByRole('button', { name: 'Copy tool details' }));
1444
+ expect(screen.queryByText('Approve Write Artifact for japan_news_2026_06_21.md?')).toBeNull();
1445
+ expect(screen.queryByText('Approve Create Document: Japan News Headlines?')).toBeNull();
1446
+ expect(screen.queryByText('deny')).toBeNull();
474
1447
 
475
- expect(writeText).toHaveBeenCalledWith(expect.stringContaining('Found 5 results'));
1448
+ expect(screen.queryByRole('button', { name: /Work needs attention/ })).toBeNull();
1449
+ fireEvent.click(screen.getByRole('button', { name: /Worked/ }));
1450
+ fireEvent.click(screen.getByRole('button', { name: /Write Artifact/ }));
1451
+
1452
+ expect(screen.getByText('Declined by user')).not.toBeNull();
1453
+ expect(screen.getAllByText(/japan_news_2026_06_21\.md/).length).toBeGreaterThan(0);
1454
+ expect(screen.getByText('Cancelled after denial')).not.toBeNull();
1455
+ fireEvent.click(screen.getByRole('button', { name: /Create Document.*Cancelled after denial/ }));
1456
+ expect(screen.getAllByText(/Japan News Headlines/).length).toBeGreaterThan(0);
476
1457
  });
477
1458
 
478
- it('does not expand tool error details by default', () => {
1459
+ it('hides a commented approval denial prompt while keeping the user comment visible', () => {
479
1460
  renderSummary(
480
1461
  [
481
1462
  makeMessage({
482
1463
  timestamp: 1_000,
483
- type: AgentMessageType.QUESTION,
484
- message: 'Publish the app.',
1464
+ type: AgentMessageType.REQUEST_INPUT,
1465
+ message: 'Approve Write Artifact: quotes.md?',
1466
+ details: {
1467
+ tool_approval: {
1468
+ approval_key: 'write_artifact:name:quotes.md',
1469
+ tool_name: 'write_artifact',
1470
+ tool_title: 'Write Artifact',
1471
+ target: 'name:quotes.md',
1472
+ input: {
1473
+ name: 'quotes.md',
1474
+ type: 'file',
1475
+ },
1476
+ },
1477
+ ux: {
1478
+ options: [
1479
+ { id: 'allow_once', label: 'Allow once' },
1480
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1481
+ { id: 'deny', label: 'Deny' },
1482
+ ],
1483
+ free_response: {
1484
+ placeholder: 'No, and tell the agent what to do differently',
1485
+ submit_label: 'Submit',
1486
+ metadata: {
1487
+ tool_approval_response: {
1488
+ decision: 'deny_with_feedback',
1489
+ approval_key: 'write_artifact:name:quotes.md',
1490
+ },
1491
+ },
1492
+ },
1493
+ },
1494
+ },
485
1495
  }),
486
1496
  makeMessage({
487
1497
  timestamp: 2_000,
488
- message: 'Publishing app...',
489
- details: {
490
- activity_group_id: 'activity-10',
491
- tool: 'app_publish',
492
- tool_run_id: 'publish-wrapper',
493
- tool_status: 'running',
494
- },
1498
+ type: AgentMessageType.QUESTION,
1499
+ message: 'Do not write a file. Put the summary in chat.',
495
1500
  }),
496
1501
  makeMessage({
497
1502
  timestamp: 3_000,
498
- type: AgentMessageType.ERROR,
499
- message: 'App publish blocked until preview validation passes',
1503
+ type: AgentMessageType.THOUGHT,
1504
+ message: 'User declined to use Write Artifact.',
500
1505
  details: {
501
- activity_group_id: 'activity-10',
502
- tool: 'app_publish',
503
- tool_run_id: 'publish-progress',
1506
+ event_class: 'activity',
1507
+ tool: 'write_artifact',
1508
+ tool_run_id: 'tool-run-1',
1509
+ tool_use_id: 'tool-use-1',
504
1510
  tool_status: 'error',
1511
+ tool_event: 'failed',
1512
+ activity_group_id: 'activity-1',
1513
+ observation: 'User declined to use Write Artifact and provided new instructions.',
1514
+ approval_decision: 'denied_with_feedback',
1515
+ approval_request: {
1516
+ approval_key: 'write_artifact:name:quotes.md',
1517
+ tool_name: 'write_artifact',
1518
+ tool_title: 'Write Artifact',
1519
+ target: 'name:quotes.md',
1520
+ },
1521
+ input: {
1522
+ name: 'quotes.md',
1523
+ type: 'file',
1524
+ },
505
1525
  },
506
1526
  }),
507
1527
  ],
508
1528
  true,
509
1529
  );
510
1530
 
511
- const workRow = screen.getByRole('button', { name: /Work needs attention\s*for\s*1s/ });
512
- fireEvent.click(workRow);
513
-
514
- const toolRow = screen.getByRole('button', { name: /Tool\s*Publishing app/ });
515
- expect(toolRow.getAttribute('aria-expanded')).toBe('false');
516
- expect(screen.queryByText('App publish blocked until preview validation passes')).toBeNull();
517
-
518
- fireEvent.click(toolRow);
519
-
520
- expect(screen.getByText('App publish blocked until preview validation passes')).not.toBeNull();
521
- });
522
-
523
- it('renders pending ask options compactly in summary view', () => {
524
- renderSummary([
525
- makeMessage({
526
- timestamp: 1_000,
527
- type: AgentMessageType.REQUEST_INPUT,
528
- message: 'What is your favorite color?',
529
- details: {
530
- ux: {
531
- options: [
532
- { id: 'red', label: 'Red', description: 'The color of fire and passion' },
533
- { id: 'blue', label: 'Blue', description: 'The color of the sky and ocean' },
534
- ],
535
- },
536
- },
537
- }),
538
- ]);
539
-
540
- expect(screen.getByText('What is your favorite color?')).not.toBeNull();
541
- expect(screen.getByRole('button', { name: /Blue\s*The color of the sky and ocean/ })).not.toBeNull();
1531
+ expect(screen.queryByText('Approve Write Artifact: quotes.md?')).toBeNull();
1532
+ expect(screen.getByText('Do not write a file. Put the summary in chat.')).not.toBeNull();
1533
+ fireEvent.click(screen.getByRole('button', { name: /Worked/ }));
1534
+ expect(screen.getByRole('button', { name: /Write Artifact.*Declined by user/ })).not.toBeNull();
542
1535
  });
543
1536
 
544
- it('keeps only the ask question after the user answers in summary view', () => {
1537
+ it('hides a commented approval denial prompt immediately from response metadata', () => {
545
1538
  renderSummary(
546
1539
  [
547
1540
  makeMessage({
548
1541
  timestamp: 1_000,
549
1542
  type: AgentMessageType.REQUEST_INPUT,
550
- message: 'What is your favorite color?',
1543
+ message: 'Approve Write Artifact: quotes.md?',
551
1544
  details: {
1545
+ tool_approval: {
1546
+ approval_key: 'write_artifact:name:quotes.md',
1547
+ tool_name: 'write_artifact',
1548
+ tool_title: 'Write Artifact',
1549
+ target: 'name:quotes.md',
1550
+ },
552
1551
  ux: {
553
1552
  options: [
554
- { id: 'red', label: 'Red', description: 'The color of fire and passion' },
555
- { id: 'blue', label: 'Blue', description: 'The color of the sky and ocean' },
1553
+ { id: 'allow_once', label: 'Allow once' },
1554
+ { id: 'allow_for_run', label: 'Allow this action for this run' },
1555
+ { id: 'deny', label: 'Deny' },
556
1556
  ],
557
1557
  },
558
1558
  },
@@ -560,16 +1560,20 @@ describe('AllMessagesMixed summary view', () => {
560
1560
  makeMessage({
561
1561
  timestamp: 2_000,
562
1562
  type: AgentMessageType.QUESTION,
563
- message: 'blue',
1563
+ message: 'Do not write a file. Put the summary in chat.',
1564
+ details: {
1565
+ tool_approval_response: {
1566
+ decision: 'deny_with_feedback',
1567
+ approval_key: 'write_artifact:name:quotes.md',
1568
+ },
1569
+ },
564
1570
  }),
565
1571
  ],
566
- true,
1572
+ false,
567
1573
  );
568
1574
 
569
- expect(screen.getByText('What is your favorite color?')).not.toBeNull();
570
- expect(screen.getByText('blue')).not.toBeNull();
571
- expect(screen.queryByText('The color of the sky and ocean')).toBeNull();
572
- expect(screen.queryByRole('button', { name: /Blue/ })).toBeNull();
1575
+ expect(screen.queryByText('Approve Write Artifact: quotes.md?')).toBeNull();
1576
+ expect(screen.getByText('Do not write a file. Put the summary in chat.')).not.toBeNull();
573
1577
  });
574
1578
 
575
1579
  it('does not duplicate the initial request once the persisted user prompt is present', () => {
@@ -625,7 +1629,7 @@ describe('AllMessagesMixed summary view', () => {
625
1629
  expect(screen.queryByRole('button', { name: /Blue/ })).toBeNull();
626
1630
  });
627
1631
 
628
- it('renders thought prose between tool rows inside expanded work details', () => {
1632
+ it('renders thought prose as a collapsed subsection inside expanded work details', () => {
629
1633
  renderSummary(
630
1634
  [
631
1635
  makeMessage({
@@ -670,7 +1674,7 @@ describe('AllMessagesMixed summary view', () => {
670
1674
  const workedRow = screen.getByRole('button', { name: /Worked\s*for\s*3s/ });
671
1675
  fireEvent.click(workedRow);
672
1676
 
673
- expect(screen.queryByText('Thought')).toBeNull();
1677
+ expect(screen.queryByRole('button', { name: /Thought: The form source is better than the UI/ })).toBeNull();
674
1678
  expect(
675
1679
  screen.getByText('The form source is better than the UI, so I will inspect the serialization path.'),
676
1680
  ).not.toBeNull();
@@ -678,7 +1682,74 @@ describe('AllMessagesMixed summary view', () => {
678
1682
  expect(screen.getByText('allowed_scopes')).not.toBeNull();
679
1683
  });
680
1684
 
681
- it('renders legacy think tool rows as thought prose in expanded summary work details', () => {
1685
+ it('collapses very long thought prose inside expanded work details', () => {
1686
+ const longThought = [
1687
+ 'Thinking through the best approach for this complex multi-repo release note generation problem...',
1688
+ '',
1689
+ 'Grant is asking me to help design a prompt strategy for release notes from GitHub repos.',
1690
+ 'This is a meta-task, so I need to help him think through the best approach and craft effective prompts.',
1691
+ '',
1692
+ 'Key challenges:',
1693
+ '',
1694
+ '1. Multi-repo complexity: 3 repos with a dependency chain.',
1695
+ '2. Filtering logic: exclude chores and infrastructure changes unless user-facing.',
1696
+ '3. Deduplication: fixes and improvements should roll into the relevant feature.',
1697
+ '4. Progressive document building: preserve context without overloading a single step.',
1698
+ '5. Review loop: make sure final release notes are concise and audience-ready.',
1699
+ '',
1700
+ 'Daily changelog approach has natural organization by time, but it creates rework.',
1701
+ 'Feature list approach is more aligned with release notes, but needs stronger discovery.',
1702
+ 'The best option is likely a hybrid: gather structured daily facts, then synthesize by feature.',
1703
+ ].join('\n');
1704
+
1705
+ renderSummary(
1706
+ [
1707
+ makeMessage({
1708
+ timestamp: 1_000,
1709
+ type: AgentMessageType.QUESTION,
1710
+ message: 'Plan release notes.',
1711
+ }),
1712
+ makeMessage({
1713
+ timestamp: 2_000,
1714
+ type: AgentMessageType.THOUGHT,
1715
+ message: longThought,
1716
+ }),
1717
+ makeMessage({
1718
+ timestamp: 3_000,
1719
+ message: 'Reading commits',
1720
+ details: {
1721
+ tool: 'read_file',
1722
+ tool_status: 'completed',
1723
+ tool_run_id: 'tool-1',
1724
+ path: 'CHANGELOG.md',
1725
+ },
1726
+ }),
1727
+ ],
1728
+ true,
1729
+ );
1730
+
1731
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
1732
+
1733
+ const showMoreButton = screen.getByRole('button', { name: /Show more/ });
1734
+ const prose = screen.getByTestId('summary-thought-prose');
1735
+ expect(showMoreButton.getAttribute('aria-expanded')).toBe('false');
1736
+ expect(prose.getAttribute('class') ?? '').toContain('[-webkit-line-clamp:6]');
1737
+ expect(showMoreButton.getAttribute('class') ?? '').not.toContain('focus-visible:underline');
1738
+ expect(showMoreButton.getAttribute('class') ?? '').not.toContain('underline-offset');
1739
+ expect(Boolean(prose.compareDocumentPosition(showMoreButton) & Node.DOCUMENT_POSITION_FOLLOWING)).toBe(true);
1740
+ expect(screen.getByText(/Thinking through the best approach/)).not.toBeNull();
1741
+ expect(screen.getByText('CHANGELOG.md')).not.toBeNull();
1742
+
1743
+ fireEvent.click(showMoreButton);
1744
+
1745
+ const showLessButton = screen.getByRole('button', { name: /Show less/ });
1746
+ expect(showLessButton.getAttribute('aria-expanded')).toBe('true');
1747
+ expect(showLessButton.getAttribute('class') ?? '').not.toContain('sticky');
1748
+ expect(prose.getAttribute('class') ?? '').not.toContain('[-webkit-line-clamp:6]');
1749
+ expect(screen.getByText(/Feature list approach is more aligned/)).not.toBeNull();
1750
+ });
1751
+
1752
+ it('renders legacy think tool rows as plain preamble prose in expanded summary work details', () => {
682
1753
  renderSummary(
683
1754
  [
684
1755
  makeMessage({
@@ -720,8 +1791,121 @@ describe('AllMessagesMixed summary view', () => {
720
1791
  fireEvent.click(workedRow);
721
1792
 
722
1793
  expect(screen.getByText('Searching for the latest news headlines from Japan...')).not.toBeNull();
1794
+ expect(
1795
+ screen.queryByRole('button', { name: /Thought: Searching for the latest news headlines from Japan/ }),
1796
+ ).toBeNull();
723
1797
  expect(screen.queryByRole('button', { name: /Tool\s+Searching for/ })).toBeNull();
724
- expect(screen.getByRole('button', { name: /Tool\s*Updating 1 tasks of our plan/ })).not.toBeNull();
1798
+ expect(screen.getByRole('button', { name: /Updating 1 tasks of our plan/ })).not.toBeNull();
1799
+ });
1800
+
1801
+ it('renders long tool preambles as plain prose with show more inside expanded summary work details', () => {
1802
+ const longPreamble = [
1803
+ 'I will now activate the web search skill so that I can look up live French news headlines.',
1804
+ 'Then I will update the plan and proceed to search for current news headlines in France.',
1805
+ 'After that I will compare French and international sources before giving a concise summary.',
1806
+ 'This should keep the tool work visible without turning this preamble into a tool row.',
1807
+ 'I will also keep the answer scoped to the current date and avoid stale coverage.',
1808
+ 'Next I will verify that the sources are current enough for the requested headline summary.',
1809
+ 'Finally I will present the findings as regular assistant prose instead of another tool row.',
1810
+ ].join('\n');
1811
+
1812
+ renderSummary(
1813
+ [
1814
+ makeMessage({
1815
+ timestamp: 1_000,
1816
+ type: AgentMessageType.QUESTION,
1817
+ message: 'What are the news headlines in France today?',
1818
+ }),
1819
+ makeMessage({
1820
+ timestamp: 2_000,
1821
+ type: AgentMessageType.THOUGHT,
1822
+ message: longPreamble,
1823
+ details: {
1824
+ display_role: 'tool_preamble',
1825
+ tools: ['learn_web_search'],
1826
+ activity_group_id: 'activity-1',
1827
+ },
1828
+ }),
1829
+ makeMessage({
1830
+ timestamp: 3_000,
1831
+ message: 'Activating the web search tool...',
1832
+ details: {
1833
+ event_class: 'activity',
1834
+ tool: 'learn_web_search',
1835
+ tool_run_id: 'tool-1',
1836
+ tool_status: 'completed',
1837
+ activity_group_id: 'activity-1',
1838
+ },
1839
+ }),
1840
+ ],
1841
+ true,
1842
+ );
1843
+
1844
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
1845
+
1846
+ expect(screen.queryByText('Thought')).toBeNull();
1847
+ expect(screen.queryByRole('button', { name: /Thought:/ })).toBeNull();
1848
+ expect(screen.getByText(/I will now activate the web search skill/)).not.toBeNull();
1849
+
1850
+ const showMoreButton = screen.getByRole('button', { name: /Show more/ });
1851
+ const prose = screen.getByTestId('summary-thought-prose');
1852
+ expect(showMoreButton.getAttribute('aria-expanded')).toBe('false');
1853
+ expect(prose.getAttribute('class') ?? '').toContain('[-webkit-line-clamp:6]');
1854
+ expect(Boolean(prose.compareDocumentPosition(showMoreButton) & Node.DOCUMENT_POSITION_FOLLOWING)).toBe(true);
1855
+ fireEvent.click(showMoreButton);
1856
+
1857
+ const showLessButton = screen.getByRole('button', { name: /Show less/ });
1858
+ expect(showLessButton.getAttribute('aria-expanded')).toBe('true');
1859
+ expect(screen.getByText(/This should keep the tool work visible/)).not.toBeNull();
1860
+ });
1861
+
1862
+ it('does not collapse long tool preambles while the summary work row is active', () => {
1863
+ const longPreamble = [
1864
+ 'I will now create a plan to retrieve the latest news headlines from France today.',
1865
+ 'To do this, I will first activate the web search skill.',
1866
+ 'Then I will search for current French news from multiple sources.',
1867
+ 'After that I will retrieve and summarize the results.',
1868
+ 'I will compare the current reports before answering.',
1869
+ 'I will keep this setup visible while the work is still running.',
1870
+ 'Finally I will produce a concise answer when the search completes.',
1871
+ ].join('\n');
1872
+
1873
+ renderSummary([
1874
+ makeMessage({
1875
+ timestamp: Date.now() - 2_000,
1876
+ type: AgentMessageType.QUESTION,
1877
+ message: 'What are the news headlines in France today?',
1878
+ }),
1879
+ makeMessage({
1880
+ timestamp: Date.now() - 1_500,
1881
+ type: AgentMessageType.THOUGHT,
1882
+ message: longPreamble,
1883
+ details: {
1884
+ display_role: 'tool_preamble',
1885
+ tools: ['learn_web_search'],
1886
+ activity_group_id: 'activity-1',
1887
+ },
1888
+ }),
1889
+ makeMessage({
1890
+ timestamp: Date.now() - 1_000,
1891
+ message: 'Creating a step-by-step plan to search for the latest headlines.',
1892
+ details: {
1893
+ event_class: 'activity',
1894
+ tool: 'update_plan',
1895
+ tool_run_id: 'tool-1',
1896
+ tool_status: 'running',
1897
+ activity_group_id: 'activity-1',
1898
+ },
1899
+ }),
1900
+ ]);
1901
+
1902
+ expect(screen.getByRole('button', { name: /Working\s*for/ }).getAttribute('aria-expanded')).toBe('true');
1903
+ expect(screen.queryByRole('button', { name: /Show more/ })).toBeNull();
1904
+ expect(screen.queryByRole('button', { name: /Show less/ })).toBeNull();
1905
+ expect(screen.getByText(/Finally I will produce a concise answer/)).not.toBeNull();
1906
+
1907
+ const prose = screen.getByTestId('summary-thought-prose');
1908
+ expect(prose.getAttribute('class') ?? '').not.toContain('[-webkit-line-clamp:6]');
725
1909
  });
726
1910
 
727
1911
  it('renders completed streaming answers as visible summary prose before later tool activity', () => {
@@ -943,4 +2127,114 @@ describe('AllMessagesMixed summary view', () => {
943
2127
  expect(screen.getByText('Found 3 relevant docs.')).not.toBeNull();
944
2128
  expect(screen.getByText('completed')).not.toBeNull();
945
2129
  });
2130
+
2131
+ it('does not render document panel events as duplicate create document tool rows', () => {
2132
+ renderSummary(
2133
+ [
2134
+ makeMessage({
2135
+ timestamp: 1_000,
2136
+ type: AgentMessageType.QUESTION,
2137
+ message: 'Create a Japan news report.',
2138
+ }),
2139
+ makeMessage({
2140
+ timestamp: 2_000,
2141
+ type: AgentMessageType.THOUGHT,
2142
+ message: 'Creating document from artifact:files/japan_news_report.md...',
2143
+ details: {
2144
+ event_class: 'activity',
2145
+ tool: 'create_document',
2146
+ tool_run_id: 'create_document',
2147
+ tool_status: 'running',
2148
+ activity_group_id: 'activity-5',
2149
+ source: 'artifact:files/japan_news_report.md',
2150
+ name: 'Japan News Headlines Today',
2151
+ tool_event: 'progress',
2152
+ },
2153
+ }),
2154
+ makeMessage({
2155
+ timestamp: 2_600,
2156
+ type: AgentMessageType.THOUGHT,
2157
+ message: 'Document [Japan News Headlines Today](store:doc-1) has been successfully created',
2158
+ details: {
2159
+ event_class: 'activity',
2160
+ tool: 'create_document',
2161
+ tool_run_id: 'create_document',
2162
+ tool_status: 'completed',
2163
+ activity_group_id: 'activity-5',
2164
+ tool_event: 'progress',
2165
+ },
2166
+ }),
2167
+ makeMessage({
2168
+ timestamp: 2_650,
2169
+ type: AgentMessageType.UPDATE,
2170
+ message: 'Created document "Japan News Headlines Today"',
2171
+ details: {
2172
+ event_class: 'document_created',
2173
+ document_id: 'doc-1',
2174
+ title: 'Japan News Headlines Today',
2175
+ },
2176
+ }),
2177
+ makeMessage({
2178
+ timestamp: 4_000,
2179
+ type: AgentMessageType.ANSWER,
2180
+ message: 'The report has been created.',
2181
+ }),
2182
+ ],
2183
+ true,
2184
+ );
2185
+
2186
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
2187
+
2188
+ expect(screen.getAllByRole('button', { name: /Japan News Headlines Today/ })).toHaveLength(1);
2189
+ expect(screen.queryByText('Created document "Japan News Headlines Today"')).toBeNull();
2190
+ });
2191
+
2192
+ it('groups artifact completion updates into the write artifact tool row', () => {
2193
+ renderSummary(
2194
+ [
2195
+ makeMessage({
2196
+ timestamp: 1_000,
2197
+ type: AgentMessageType.QUESTION,
2198
+ message: 'Write the report to an artifact.',
2199
+ }),
2200
+ makeMessage({
2201
+ timestamp: 2_000,
2202
+ type: AgentMessageType.THOUGHT,
2203
+ message: 'Writing the compiled news report to the temporary workspace artifact...',
2204
+ details: {
2205
+ event_class: 'activity',
2206
+ tool: 'write_artifact',
2207
+ tool_run_id: 'write_artifact',
2208
+ tool_use_id: 'write_artifact',
2209
+ tool_status: 'running',
2210
+ tool_event: 'started',
2211
+ activity_group_id: 'activity-write',
2212
+ message_to_human: 'Writing the compiled news report to the temporary workspace artifact...',
2213
+ },
2214
+ }),
2215
+ makeMessage({
2216
+ timestamp: 3_000,
2217
+ type: AgentMessageType.UPDATE,
2218
+ message: 'Prepared and saved artifact to files/US_News_Report_2026-06-22.md',
2219
+ details: {
2220
+ path: 'files/US_News_Report_2026-06-22.md',
2221
+ size: 4426,
2222
+ },
2223
+ }),
2224
+ ],
2225
+ true,
2226
+ );
2227
+
2228
+ fireEvent.click(screen.getByRole('button', { name: /Worked\s*for/ }));
2229
+
2230
+ const writeRow = screen.getByRole('button', {
2231
+ name: /Writing the compiled news report to the temporary workspace artifact/,
2232
+ });
2233
+ expect(writeRow).not.toBeNull();
2234
+ expect(screen.queryByRole('button', { name: /files\/US_News_Report_2026-06-22\.md/ })).toBeNull();
2235
+
2236
+ fireEvent.click(writeRow);
2237
+
2238
+ expect(screen.getByText('Prepared and saved artifact to files/US_News_Report_2026-06-22.md')).not.toBeNull();
2239
+ });
946
2240
  });