@vertesia/ui 1.5.0-dev.20260722.120446Z → 1.5.0-dev.20260725.083715Z

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 (307) hide show
  1. package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  2. package/lib/core/components/shadcn/filters/filterBar.js +1 -1
  3. package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
  4. package/lib/core/components/shadcn/modal/dialog.d.ts +1 -1
  5. package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
  6. package/lib/core/components/shadcn/modal/dialog.js +2 -0
  7. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  8. package/lib/core/components/shadcn/tabs.d.ts +12 -1
  9. package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
  10. package/lib/core/components/shadcn/tabs.js +12 -4
  11. package/lib/core/components/shadcn/tabs.js.map +1 -1
  12. package/lib/features/agent/chat/AgentRightPanel.d.ts +5 -1
  13. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  14. package/lib/features/agent/chat/AgentRightPanel.js +2 -2
  15. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  16. package/lib/features/agent/chat/ArtifactsTab.d.ts +5 -1
  17. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  18. package/lib/features/agent/chat/ArtifactsTab.js +48 -11
  19. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  20. package/lib/features/agent/chat/DocumentEditingActionCard.d.ts +6 -0
  21. package/lib/features/agent/chat/DocumentEditingActionCard.d.ts.map +1 -0
  22. package/lib/features/agent/chat/DocumentEditingActionCard.js +129 -0
  23. package/lib/features/agent/chat/DocumentEditingActionCard.js.map +1 -0
  24. package/lib/features/agent/chat/ModernAgentConversation.d.ts +19 -1
  25. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  26. package/lib/features/agent/chat/ModernAgentConversation.js +125 -27
  27. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  28. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts +45 -0
  29. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts.map +1 -0
  30. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js +40 -0
  31. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js.map +1 -0
  32. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
  33. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  34. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +94 -49
  35. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  36. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts +2 -1
  37. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
  38. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +9 -5
  39. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
  40. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts +25 -0
  41. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts.map +1 -0
  42. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js +33 -0
  43. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js.map +1 -0
  44. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
  45. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  46. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +22 -24
  47. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  48. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts +14 -0
  49. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts.map +1 -0
  50. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js +21 -0
  51. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js.map +1 -0
  52. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts +30 -0
  53. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts.map +1 -0
  54. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js +53 -0
  55. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js.map +1 -0
  56. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
  57. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +21 -2
  58. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
  59. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts +6 -0
  60. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts.map +1 -0
  61. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js +29 -0
  62. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js.map +1 -0
  63. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts +33 -0
  64. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts.map +1 -0
  65. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js +129 -0
  66. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js.map +1 -0
  67. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +7 -0
  68. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
  69. package/lib/features/agent/chat/ModernAgentOutput/utils.js +11 -1
  70. package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
  71. package/lib/features/agent/chat/hooks/useAgentStream.d.ts +1 -1
  72. package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  73. package/lib/features/agent/chat/hooks/useAgentStream.js +24 -9
  74. package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  75. package/lib/features/agent/chat/index.d.ts +2 -1
  76. package/lib/features/agent/chat/index.d.ts.map +1 -1
  77. package/lib/features/agent/chat/index.js +3 -0
  78. package/lib/features/agent/chat/index.js.map +1 -1
  79. package/lib/features/store/objects/DocumentSearchResults.js +2 -2
  80. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  81. package/lib/features/store/objects/components/ContentOverview.d.ts +2 -1
  82. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  83. package/lib/features/store/objects/components/ContentOverview.js +86 -15
  84. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  85. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts +16 -0
  86. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts.map +1 -0
  87. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js +116 -0
  88. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js.map +1 -0
  89. package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts +7 -0
  90. package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts.map +1 -0
  91. package/lib/features/store/objects/components/DocumentEditingLockStatus.js +13 -0
  92. package/lib/features/store/objects/components/DocumentEditingLockStatus.js.map +1 -0
  93. package/lib/features/store/objects/components/DocumentEditingPanel.d.ts +48 -0
  94. package/lib/features/store/objects/components/DocumentEditingPanel.d.ts.map +1 -0
  95. package/lib/features/store/objects/components/DocumentEditingPanel.js +720 -0
  96. package/lib/features/store/objects/components/DocumentEditingPanel.js.map +1 -0
  97. package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
  98. package/lib/features/store/objects/components/TextEditorPanel.js +22 -9
  99. package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
  100. package/lib/features/store/objects/components/documentArtifactRefs.d.ts +26 -0
  101. package/lib/features/store/objects/components/documentArtifactRefs.d.ts.map +1 -0
  102. package/lib/features/store/objects/components/documentArtifactRefs.js +52 -0
  103. package/lib/features/store/objects/components/documentArtifactRefs.js.map +1 -0
  104. package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts +4 -0
  105. package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts.map +1 -0
  106. package/lib/features/store/objects/components/documentEditingAgentConfig.js +40 -0
  107. package/lib/features/store/objects/components/documentEditingAgentConfig.js.map +1 -0
  108. package/lib/features/store/objects/components/documentEditingPrompts.d.ts +3 -0
  109. package/lib/features/store/objects/components/documentEditingPrompts.d.ts.map +1 -0
  110. package/lib/features/store/objects/components/documentEditingPrompts.js +13 -0
  111. package/lib/features/store/objects/components/documentEditingPrompts.js.map +1 -0
  112. package/lib/features/store/objects/components/documentEditingRun.d.ts +27 -0
  113. package/lib/features/store/objects/components/documentEditingRun.d.ts.map +1 -0
  114. package/lib/features/store/objects/components/documentEditingRun.js +126 -0
  115. package/lib/features/store/objects/components/documentEditingRun.js.map +1 -0
  116. package/lib/features/store/objects/components/documentEditingTarget.d.ts +20 -0
  117. package/lib/features/store/objects/components/documentEditingTarget.d.ts.map +1 -0
  118. package/lib/features/store/objects/components/documentEditingTarget.js +40 -0
  119. package/lib/features/store/objects/components/documentEditingTarget.js.map +1 -0
  120. package/lib/features/store/objects/components/index.d.ts +1 -0
  121. package/lib/features/store/objects/components/index.d.ts.map +1 -1
  122. package/lib/features/store/objects/components/index.js +1 -0
  123. package/lib/features/store/objects/components/index.js.map +1 -1
  124. package/lib/features/store/objects/components/useContentPanelHooks.d.ts +5 -1
  125. package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  126. package/lib/features/store/objects/components/useContentPanelHooks.js +53 -29
  127. package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
  128. package/lib/features/store/objects/components/useDownloadFile.d.ts +2 -1
  129. package/lib/features/store/objects/components/useDownloadFile.d.ts.map +1 -1
  130. package/lib/features/store/objects/components/useDownloadFile.js +3 -0
  131. package/lib/features/store/objects/components/useDownloadFile.js.map +1 -1
  132. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +1 -1
  133. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +1 -1
  134. package/lib/i18n/locales/ar.json +118 -1
  135. package/lib/i18n/locales/de.json +118 -1
  136. package/lib/i18n/locales/en.json +118 -0
  137. package/lib/i18n/locales/es.json +118 -1
  138. package/lib/i18n/locales/fr.json +118 -1
  139. package/lib/i18n/locales/it.json +118 -1
  140. package/lib/i18n/locales/ja.json +118 -1
  141. package/lib/i18n/locales/ko.json +118 -1
  142. package/lib/i18n/locales/pt.json +118 -1
  143. package/lib/i18n/locales/ru.json +118 -1
  144. package/lib/i18n/locales/tr.json +118 -1
  145. package/lib/i18n/locales/zh-TW.json +118 -1
  146. package/lib/i18n/locales/zh.json +118 -1
  147. package/lib/rich-text/EditorToolbar.d.ts +37 -0
  148. package/lib/rich-text/EditorToolbar.d.ts.map +1 -0
  149. package/lib/rich-text/EditorToolbar.js +215 -0
  150. package/lib/rich-text/EditorToolbar.js.map +1 -0
  151. package/lib/rich-text/VertesiaRichTextEditor.d.ts +26 -0
  152. package/lib/rich-text/VertesiaRichTextEditor.d.ts.map +1 -0
  153. package/lib/rich-text/VertesiaRichTextEditor.js +67 -0
  154. package/lib/rich-text/VertesiaRichTextEditor.js.map +1 -0
  155. package/lib/rich-text/index.d.ts +2 -0
  156. package/lib/rich-text/index.d.ts.map +1 -0
  157. package/lib/rich-text/index.js +2 -0
  158. package/lib/rich-text/index.js.map +1 -0
  159. package/lib/vertesia-ui-core.js +2 -2
  160. package/lib/vertesia-ui-core.js.map +1 -1
  161. package/lib/vertesia-ui-features.js +35 -30
  162. package/lib/vertesia-ui-features.js.map +1 -1
  163. package/lib/vertesia-ui-i18n.js +14 -14
  164. package/lib/vertesia-ui-i18n.js.map +1 -1
  165. package/lib/vertesia-ui-rich-text.js +5 -0
  166. package/lib/vertesia-ui-rich-text.js.map +1 -0
  167. package/lib/vertesia-ui-widgets.js +25 -7
  168. package/lib/vertesia-ui-widgets.js.map +1 -1
  169. package/lib/widgets/markdown/AgentResourceResolver.d.ts +31 -0
  170. package/lib/widgets/markdown/AgentResourceResolver.d.ts.map +1 -0
  171. package/lib/widgets/markdown/AgentResourceResolver.js +39 -0
  172. package/lib/widgets/markdown/AgentResourceResolver.js.map +1 -0
  173. package/lib/widgets/markdown/ArtifactEditingSurface.d.ts +63 -0
  174. package/lib/widgets/markdown/ArtifactEditingSurface.d.ts.map +1 -0
  175. package/lib/widgets/markdown/ArtifactEditingSurface.js +582 -0
  176. package/lib/widgets/markdown/ArtifactEditingSurface.js.map +1 -0
  177. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts +69 -0
  178. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts.map +1 -0
  179. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js +374 -0
  180. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js.map +1 -0
  181. package/lib/widgets/markdown/MarkdownLink.d.ts +3 -1
  182. package/lib/widgets/markdown/MarkdownLink.d.ts.map +1 -1
  183. package/lib/widgets/markdown/MarkdownLink.js +41 -14
  184. package/lib/widgets/markdown/MarkdownLink.js.map +1 -1
  185. package/lib/widgets/markdown/MarkdownRenderer.d.ts +8 -1
  186. package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  187. package/lib/widgets/markdown/MarkdownRenderer.js +20 -4
  188. package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
  189. package/lib/widgets/markdown/index.d.ts +5 -1
  190. package/lib/widgets/markdown/index.d.ts.map +1 -1
  191. package/lib/widgets/markdown/index.js +5 -1
  192. package/lib/widgets/markdown/index.js.map +1 -1
  193. package/lib/widgets/markdown/normalizeCustomSchemeLinks.d.ts.map +1 -1
  194. package/lib/widgets/markdown/normalizeCustomSchemeLinks.js +14 -2
  195. package/lib/widgets/markdown/normalizeCustomSchemeLinks.js.map +1 -1
  196. package/lib/widgets/markdown/textDiff.d.ts +52 -0
  197. package/lib/widgets/markdown/textDiff.d.ts.map +1 -0
  198. package/lib/widgets/markdown/textDiff.js +362 -0
  199. package/lib/widgets/markdown/textDiff.js.map +1 -0
  200. package/lib/widgets/markdown/useArtifactContent.d.ts +5 -3
  201. package/lib/widgets/markdown/useArtifactContent.d.ts.map +1 -1
  202. package/lib/widgets/markdown/useArtifactContent.js +6 -3
  203. package/lib/widgets/markdown/useArtifactContent.js.map +1 -1
  204. package/lib/widgets/markdown/useResolvedUrl.d.ts +1 -5
  205. package/lib/widgets/markdown/useResolvedUrl.d.ts.map +1 -1
  206. package/lib/widgets/markdown/useResolvedUrl.js +19 -31
  207. package/lib/widgets/markdown/useResolvedUrl.js.map +1 -1
  208. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +9 -0
  209. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
  210. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +20 -17
  211. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
  212. package/package.json +13 -9
  213. package/src/__tests__/a11y.test.tsx +4 -1
  214. package/src/__tests__/axe-helper.ts +17 -7
  215. package/src/__tests__/setup.ts +25 -0
  216. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  217. package/src/core/components/shadcn/modal/dialog.tsx +3 -1
  218. package/src/core/components/shadcn/tabs.test.tsx +65 -0
  219. package/src/core/components/shadcn/tabs.tsx +25 -3
  220. package/src/features/agent/chat/AgentRightPanel.tsx +16 -1
  221. package/src/features/agent/chat/ArtifactsTab.test.tsx +55 -0
  222. package/src/features/agent/chat/ArtifactsTab.tsx +203 -52
  223. package/src/features/agent/chat/DocumentEditingActionCard.test.tsx +105 -0
  224. package/src/features/agent/chat/DocumentEditingActionCard.tsx +210 -0
  225. package/src/features/agent/chat/ModernAgentConversation.test.tsx +237 -40
  226. package/src/features/agent/chat/ModernAgentConversation.tsx +247 -75
  227. package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.test.tsx +79 -0
  228. package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.tsx +94 -0
  229. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +257 -34
  230. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +217 -105
  231. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +17 -0
  232. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.test.tsx +44 -0
  233. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx +88 -0
  234. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +30 -46
  235. package/src/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.tsx +40 -0
  236. package/src/features/agent/chat/ModernAgentOutput/ResourceChip.test.tsx +148 -0
  237. package/src/features/agent/chat/ModernAgentOutput/ResourceChip.tsx +141 -0
  238. package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +33 -1
  239. package/src/features/agent/chat/ModernAgentOutput/resourceLinks.tsx +43 -0
  240. package/src/features/agent/chat/ModernAgentOutput/resourceSummary.test.ts +229 -0
  241. package/src/features/agent/chat/ModernAgentOutput/resourceSummary.ts +152 -0
  242. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +17 -0
  243. package/src/features/agent/chat/ModernAgentOutput/utils.ts +14 -1
  244. package/src/features/agent/chat/hooks/useAgentStream.test.tsx +188 -0
  245. package/src/features/agent/chat/hooks/useAgentStream.ts +28 -8
  246. package/src/features/agent/chat/index.ts +11 -0
  247. package/src/features/store/objects/DocumentSearchResults.tsx +2 -2
  248. package/src/features/store/objects/components/ContentOverview.tsx +216 -65
  249. package/src/features/store/objects/components/DocumentEditingConfigurationSelector.test.ts +34 -0
  250. package/src/features/store/objects/components/DocumentEditingConfigurationSelector.tsx +211 -0
  251. package/src/features/store/objects/components/DocumentEditingLockStatus.test.tsx +32 -0
  252. package/src/features/store/objects/components/DocumentEditingLockStatus.tsx +45 -0
  253. package/src/features/store/objects/components/DocumentEditingPanel.test.tsx +336 -0
  254. package/src/features/store/objects/components/DocumentEditingPanel.tsx +1236 -0
  255. package/src/features/store/objects/components/TextEditorPanel.test.tsx +48 -0
  256. package/src/features/store/objects/components/TextEditorPanel.tsx +41 -20
  257. package/src/features/store/objects/components/documentArtifactRefs.test.ts +65 -0
  258. package/src/features/store/objects/components/documentArtifactRefs.ts +72 -0
  259. package/src/features/store/objects/components/documentEditingAgentConfig.test.ts +28 -0
  260. package/src/features/store/objects/components/documentEditingAgentConfig.ts +41 -0
  261. package/src/features/store/objects/components/documentEditingPrompts.test.ts +26 -0
  262. package/src/features/store/objects/components/documentEditingPrompts.ts +12 -0
  263. package/src/features/store/objects/components/documentEditingRun.test.ts +176 -0
  264. package/src/features/store/objects/components/documentEditingRun.ts +184 -0
  265. package/src/features/store/objects/components/documentEditingTarget.test.ts +96 -0
  266. package/src/features/store/objects/components/documentEditingTarget.ts +63 -0
  267. package/src/features/store/objects/components/index.ts +1 -0
  268. package/src/features/store/objects/components/useContentPanelHooks.ts +52 -27
  269. package/src/features/store/objects/components/useDownloadFile.test.ts +20 -0
  270. package/src/features/store/objects/components/useDownloadFile.ts +5 -1
  271. package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +2 -2
  272. package/src/i18n/locales/ar.json +118 -1
  273. package/src/i18n/locales/de.json +118 -1
  274. package/src/i18n/locales/en.json +118 -0
  275. package/src/i18n/locales/es.json +118 -1
  276. package/src/i18n/locales/fr.json +118 -1
  277. package/src/i18n/locales/it.json +118 -1
  278. package/src/i18n/locales/ja.json +118 -1
  279. package/src/i18n/locales/ko.json +118 -1
  280. package/src/i18n/locales/pt.json +118 -1
  281. package/src/i18n/locales/ru.json +118 -1
  282. package/src/i18n/locales/tr.json +118 -1
  283. package/src/i18n/locales/zh-TW.json +118 -1
  284. package/src/i18n/locales/zh.json +118 -1
  285. package/src/rich-text/EditorToolbar.tsx +708 -0
  286. package/src/rich-text/VertesiaRichTextEditor.test.tsx +211 -0
  287. package/src/rich-text/VertesiaRichTextEditor.tsx +241 -0
  288. package/src/rich-text/index.ts +9 -0
  289. package/src/session/UserSession.test.ts +11 -11
  290. package/src/widgets/markdown/AgentResourceResolver.test.ts +24 -0
  291. package/src/widgets/markdown/AgentResourceResolver.tsx +70 -0
  292. package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +537 -0
  293. package/src/widgets/markdown/ArtifactEditingSurface.tsx +878 -0
  294. package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +484 -0
  295. package/src/widgets/markdown/CollaborativeMarkdownRenderer.tsx +825 -0
  296. package/src/widgets/markdown/MarkdownLink.test.tsx +122 -0
  297. package/src/widgets/markdown/MarkdownLink.tsx +102 -17
  298. package/src/widgets/markdown/MarkdownRenderer.tsx +30 -3
  299. package/src/widgets/markdown/index.ts +39 -1
  300. package/src/widgets/markdown/normalizeCustomSchemeLinks.ts +15 -2
  301. package/src/widgets/markdown/textDiff.test.ts +156 -0
  302. package/src/widgets/markdown/textDiff.ts +399 -0
  303. package/src/widgets/markdown/useArtifactContent.ts +9 -3
  304. package/src/widgets/markdown/useResolvedUrl.test.ts +29 -40
  305. package/src/widgets/markdown/useResolvedUrl.ts +33 -35
  306. package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +26 -0
  307. package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +23 -18
@@ -30,6 +30,11 @@ import {
30
30
  } from '@vertesia/ui/core';
31
31
  import { useUITranslation } from '@vertesia/ui/i18n';
32
32
  import { useUserSession } from '@vertesia/ui/session';
33
+ import {
34
+ type AgentResourceResolver,
35
+ AgentResourceResolverProvider,
36
+ isArtifactRefreshEvent,
37
+ } from '@vertesia/ui/widgets';
33
38
  import { ArrowUpIcon, Bot, CheckCircle, Cpu, FileTextIcon, UploadIcon, XIcon } from 'lucide-react';
34
39
  import type React from 'react';
35
40
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
@@ -69,6 +74,7 @@ import {
69
74
  getConversationUrl,
70
75
  getWorkstreamId,
71
76
  isInProgress,
77
+ isPassiveArtifactUpdate,
72
78
  } from './ModernAgentOutput/utils';
73
79
  import {
74
80
  type AgentChatPlaybackCursor,
@@ -97,6 +103,8 @@ export type StartWorkflowFn = (
97
103
  options?: StartWorkflowOptions,
98
104
  ) => Promise<{ agent_run_id: string } | undefined>;
99
105
 
106
+ export type SendAgentMessageFn = (message: string, inputMetadata?: Record<string, unknown>) => void;
107
+
100
108
  const EMPTY_STREAMING_MESSAGES = new Map<string, never>();
101
109
 
102
110
  function getTimestampMs(timestamp: number | string | undefined): number {
@@ -533,6 +541,12 @@ function downloadJsonFile(filename: string, payload: unknown) {
533
541
  export interface ModernAgentConversationProps {
534
542
  /** Stable AgentRun ID — the primary identifier for all runtime operations. */
535
543
  agentRunId?: string;
544
+ /**
545
+ * Optional override for mapping agent resource references (documents, collections, interactions,
546
+ * ...) to navigation or activation targets in the chat. This overrides an inherited
547
+ * AgentResourceResolverProvider; without either, resources remain non-interactive.
548
+ */
549
+ resourceResolver?: AgentResourceResolver;
536
550
  title?: string;
537
551
  interactive?: boolean;
538
552
  onClose?: () => void;
@@ -567,6 +581,12 @@ export interface ModernAgentConversationProps {
567
581
 
568
582
  /** Ref populated with the internal file upload handler for external triggering */
569
583
  fileUploadRef?: React.MutableRefObject<((files: File[]) => void) | null>;
584
+ /** Ref populated with the internal message sender for document or artifact collaboration controls. */
585
+ sendMessageRef?: React.MutableRefObject<SendAgentMessageFn | null>;
586
+ /** Called for each live message delivered after the conversation stream connects. */
587
+ onMessage?: (message: AgentMessage) => void;
588
+ /** Called when the main agent turn starts or reaches an idle/terminal state. */
589
+ onAgentWorkingChange?: (isWorking: boolean) => void;
570
590
  /** Called when processingFiles state changes (for external progress display) */
571
591
  onProcessingFilesChange?: (files: Map<string, ConversationFile>) => void;
572
592
  /** Processing files to display in the right panel Uploads tab */
@@ -607,6 +627,8 @@ export interface ModernAgentConversationProps {
607
627
  hideHeader?: boolean;
608
628
  /** Header density. Use compact when the surrounding page already identifies the run. */
609
629
  headerVariant?: 'full' | 'compact';
630
+ /** Start-screen layout. Compact removes empty history; expanded-composer gives that space to the first input. */
631
+ startViewVariant?: 'default' | 'compact' | 'expanded-composer';
610
632
  /** Hide the internal message input (for apps that render their own) */
611
633
  hideMessageInput?: boolean;
612
634
  /** Custom action shown in place of the input box when the run status is FAILED.
@@ -643,6 +665,8 @@ export interface ModernAgentConversationProps {
643
665
  inputContainerClassName?: string;
644
666
  /** Additional className for the input field */
645
667
  inputClassName?: string;
668
+ /** Read-only context rendered immediately above the live conversation composer. */
669
+ composerContext?: React.ReactNode;
646
670
 
647
671
  /** Additional className for the root container */
648
672
  className?: string;
@@ -708,14 +732,19 @@ export interface ModernAgentConversationProps {
708
732
  }
709
733
 
710
734
  export function ModernAgentConversation(props: ModernAgentConversationProps) {
711
- const { agentRunId, startWorkflow } = props;
735
+ const { agentRunId, startWorkflow, resourceResolver } = props;
712
736
 
713
737
  if (agentRunId) {
714
- return (
738
+ const conversation = (
715
739
  <SkillWidgetProvider>
716
740
  <ModernAgentConversationInner {...props} agentRunId={agentRunId} />
717
741
  </SkillWidgetProvider>
718
742
  );
743
+ return resourceResolver ? (
744
+ <AgentResourceResolverProvider value={resourceResolver}>{conversation}</AgentResourceResolverProvider>
745
+ ) : (
746
+ conversation
747
+ );
719
748
  } else if (startWorkflow) {
720
749
  // If we have startWorkflow capability but no agentRunId yet
721
750
  return <StartWorkflowView {...props} />;
@@ -758,13 +787,17 @@ function StartWorkflowView({
758
787
  hideFileUpload = false,
759
788
  hideObjectLinking,
760
789
  headerVariant,
790
+ startViewVariant = 'default',
761
791
  inputContainerClassName,
762
792
  inputClassName,
763
793
  className,
764
794
  allowWorkflowControl,
765
795
  initialToolApprovalMode,
796
+ onAgentWorkingChange,
766
797
  }: ModernAgentConversationProps) {
767
798
  const { t } = useUITranslation();
799
+ const isCompactStartView = startViewVariant !== 'default';
800
+ const isExpandedStartComposer = startViewVariant === 'expanded-composer';
768
801
  const canStageFiles = !hideFileUpload;
769
802
  const resolvedPlaceholder = placeholder ?? t('agent.typeYourMessage');
770
803
  const resolvedStartButtonText = startButtonText ?? t('agent.startAgent');
@@ -785,6 +818,10 @@ function StartWorkflowView({
785
818
  // Staged files - stored locally until workflow starts
786
819
  const [stagedFiles, setStagedFiles] = useState<File[]>([]);
787
820
 
821
+ useEffect(() => {
822
+ onAgentWorkingChange?.(isSending);
823
+ }, [isSending, onAgentWorkingChange]);
824
+
788
825
  // Drag and drop state
789
826
  const [isDragOver, setIsDragOver] = useState(false);
790
827
  const dragCounterRef = useRef(0);
@@ -1021,10 +1058,14 @@ function StartWorkflowView({
1021
1058
  const adjustTextareaHeight = useCallback(() => {
1022
1059
  const textarea = inputRef.current;
1023
1060
  if (textarea) {
1061
+ if (isExpandedStartComposer) {
1062
+ textarea.style.height = '100%';
1063
+ return;
1064
+ }
1024
1065
  textarea.style.height = 'auto';
1025
1066
  textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
1026
1067
  }
1027
- }, []);
1068
+ }, [isExpandedStartComposer]);
1028
1069
 
1029
1070
  useEffect(() => {
1030
1071
  void inputValue;
@@ -1049,6 +1090,7 @@ function StartWorkflowView({
1049
1090
  inputClassName,
1050
1091
  className,
1051
1092
  allowWorkflowControl,
1093
+ onAgentWorkingChange,
1052
1094
  }}
1053
1095
  agentRunId={startedAgentRunId}
1054
1096
  title={title}
@@ -1060,11 +1102,18 @@ function StartWorkflowView({
1060
1102
  }
1061
1103
 
1062
1104
  return (
1063
- <div className={cn('flex h-full flex-col items-center bg-background', className)}>
1105
+ <div
1106
+ className={cn(
1107
+ 'flex flex-col items-center bg-background',
1108
+ isCompactStartView && !isExpandedStartComposer ? '' : 'h-full',
1109
+ className,
1110
+ )}
1111
+ >
1064
1112
  {/* biome-ignore lint/a11y/noStaticElementInteractions: drag/drop target only; file selection is also exposed via the upload button. */}
1065
1113
  <div
1066
1114
  className={cn(
1067
- 'relative flex h-full w-full flex-col overflow-hidden border-0',
1115
+ 'relative flex w-full flex-col overflow-hidden border-0',
1116
+ isCompactStartView && !isExpandedStartComposer ? '' : 'h-full',
1068
1117
  fullWidth ? '' : 'max-w-4xl',
1069
1118
  )}
1070
1119
  onDragEnter={canStageFiles ? handleDragEnter : undefined}
@@ -1120,11 +1169,21 @@ function StartWorkflowView({
1120
1169
  )}
1121
1170
 
1122
1171
  {/* Empty conversation area with instructions */}
1123
- <div className="flex flex-1 flex-col items-center justify-end overflow-y-auto bg-background px-4">
1172
+ <div
1173
+ className={cn(
1174
+ 'flex flex-col items-center justify-end bg-background px-4',
1175
+ isCompactStartView ? 'shrink-0 pt-3' : 'flex-1 overflow-y-auto',
1176
+ )}
1177
+ >
1124
1178
  {pendingStartMessage && pendingStartTimestamp ? (
1125
1179
  <PendingStartConversation message={pendingStartMessage} startedAt={pendingStartTimestamp} />
1126
1180
  ) : (
1127
- <div className="mx-auto flex min-h-full w-full max-w-3xl flex-col justify-end py-8">
1181
+ <div
1182
+ className={cn(
1183
+ 'mx-auto flex w-full max-w-3xl flex-col justify-end',
1184
+ isCompactStartView ? '' : 'min-h-full py-8',
1185
+ )}
1186
+ >
1128
1187
  {initialMessage && (
1129
1188
  <div className="text-[15px] leading-relaxed text-foreground/80">{initialMessage}</div>
1130
1189
  )}
@@ -1133,10 +1192,16 @@ function StartWorkflowView({
1133
1192
  </div>
1134
1193
 
1135
1194
  {/* Input Area */}
1136
- <div className="shrink-0 bg-background px-4 pb-safe-area-4 pt-2">
1195
+ <div
1196
+ className={cn(
1197
+ 'bg-background px-4 pb-safe-area-4 pt-2',
1198
+ isExpandedStartComposer ? 'flex min-h-0 flex-1 flex-col' : 'shrink-0',
1199
+ )}
1200
+ >
1137
1201
  <div
1138
1202
  className={cn(
1139
1203
  'mx-auto flex max-w-3xl flex-col gap-3 rounded-2xl border border-border/70 bg-mixer-muted/15 p-3 shadow-lg shadow-black/5',
1204
+ isExpandedStartComposer && 'min-h-0 w-full flex-1',
1140
1205
  inputContainerClassName,
1141
1206
  )}
1142
1207
  >
@@ -1176,9 +1241,14 @@ function StartWorkflowView({
1176
1241
  rows={2}
1177
1242
  className={cn(
1178
1243
  'min-h-[72px] resize-none overflow-hidden border-0 bg-transparent px-0 py-0 text-sm leading-6 shadow-none focus-visible:ring-0',
1244
+ isExpandedStartComposer && 'min-h-0 flex-1',
1179
1245
  inputClassName,
1180
1246
  )}
1181
- style={{ minHeight: '72px', maxHeight: '200px' }}
1247
+ style={
1248
+ isExpandedStartComposer
1249
+ ? { minHeight: '72px', maxHeight: 'none' }
1250
+ : { minHeight: '72px', maxHeight: '200px' }
1251
+ }
1182
1252
  />
1183
1253
 
1184
1254
  <div className="flex items-center justify-between gap-3">
@@ -1274,10 +1344,14 @@ function ModernAgentConversationInner({
1274
1344
  className,
1275
1345
  inputContainerClassName,
1276
1346
  inputClassName,
1347
+ composerContext,
1277
1348
  // Fusion fragment data
1278
1349
  fusionData,
1279
1350
  // External file upload API
1280
1351
  fileUploadRef,
1352
+ sendMessageRef,
1353
+ onMessage,
1354
+ onAgentWorkingChange,
1281
1355
  onProcessingFilesChange,
1282
1356
  processingFiles: processingFilesProp,
1283
1357
  // External plan panel API
@@ -1338,7 +1412,7 @@ function ModernAgentConversationInner({
1338
1412
  agentRunStatus,
1339
1413
  workflowRunId,
1340
1414
  serverFileUpdates,
1341
- } = useAgentStream(client, agentRunId);
1415
+ } = useAgentStream(client, agentRunId, onMessage);
1342
1416
 
1343
1417
  const {
1344
1418
  plans,
@@ -1548,9 +1622,10 @@ function ModernAgentConversationInner({
1548
1622
  const canShowPlaybackToggle = showPlaybackToggle && enablePlayback === undefined && isAgentChatPlaybackAvailable();
1549
1623
  const isPlaybackEnabled = enablePlayback ?? (isAgentChatPlaybackEnabled() || isPlaybackToggleEnabled);
1550
1624
  const playbackSourceMessages = useMemo(() => {
1551
- const visibleMessages = hiddenMessageTypes?.length
1552
- ? messages.filter((message) => !hiddenMessageTypes.includes(message.type))
1553
- : messages;
1625
+ // Passive artifact autosaves are surfaced by the editor's own save indicator, not the chat.
1626
+ const visibleMessages = messages.filter(
1627
+ (message) => !isPassiveArtifactUpdate(message) && !(hiddenMessageTypes?.includes(message.type) ?? false),
1628
+ );
1554
1629
  return filterMessagesForActiveWorkstream(visibleMessages, activeWorkstream);
1555
1630
  }, [activeWorkstream, hiddenMessageTypes, messages]);
1556
1631
  const playbackState = useMemo(
@@ -1573,11 +1648,20 @@ function ModernAgentConversationInner({
1573
1648
  );
1574
1649
  const effectiveIsCompleted = useMemo(() => isCompleted || !isInProgress(messages), [isCompleted, messages]);
1575
1650
  const displayedIsCompleted = isPlaybackLive || isPlaybackAtLatest ? effectiveIsCompleted : false;
1651
+ const isAgentWorking = !effectiveIsCompleted && !isWorkflowTerminal;
1652
+
1653
+ useEffect(() => {
1654
+ onAgentWorkingChange?.(isAgentWorking);
1655
+ }, [isAgentWorking, onAgentWorkingChange]);
1576
1656
  const pendingRequestInputMessage = useMemo(
1577
1657
  () => getPendingRequestInputMessage(displayedMessages),
1578
1658
  [displayedMessages],
1579
1659
  );
1580
- const shouldShowRequestInputOverlay = Boolean(pendingRequestInputMessage) && !isFailed;
1660
+ // A terminal run silently drops user input unless it can be continued (see the guard in
1661
+ // handleSendMessage), so never surface an actionable question overlay in that state —
1662
+ // the terminal status box renders instead.
1663
+ const shouldShowRequestInputOverlay =
1664
+ Boolean(pendingRequestInputMessage) && !isFailed && (!isWorkflowTerminal || canContinueConversation);
1581
1665
  const isViewingPlaybackHistory = isPlaybackEnabled && !isPlaybackLive;
1582
1666
  const shouldRenderLiveMessageInputArea = shouldRenderMessageInputArea && !isViewingPlaybackHistory;
1583
1667
  const contextWindowUsage = useMemo(() => toContextWindowUsage(messages), [messages]);
@@ -1672,15 +1756,6 @@ function ModernAgentConversationInner({
1672
1756
  // ────────────────────────────────────────────
1673
1757
  // Stable callbacks
1674
1758
  // ────────────────────────────────────────────
1675
- const handleTogglePlanPanel = useCallback(() => {
1676
- setShowSlidingPanel((prev: boolean) => {
1677
- if (!prev) {
1678
- sessionStorage.setItem('plan-panel-shown', 'true');
1679
- }
1680
- return !prev;
1681
- });
1682
- }, [setShowSlidingPanel]);
1683
-
1684
1759
  const handleChangePlan = useCallback(
1685
1760
  (index: number) => {
1686
1761
  setActivePlanIndex(index);
@@ -1695,17 +1770,44 @@ function ModernAgentConversationInner({
1695
1770
  const [rightPanelTab, setRightPanelTab] = useState<RightPanelTab>(
1696
1771
  conversationContent || conversationTab ? 'conversation' : 'plan',
1697
1772
  );
1773
+ const [selectedArtifactPath, setSelectedArtifactPath] = useState<string | null>(null);
1698
1774
  const [rightPanelWidth, setRightPanelWidth] = useState(400);
1699
1775
  const [isRightPanelResizing, setIsRightPanelResizing] = useState(false);
1776
+ // Master override for the "Toggle right sidebar" control. `showSlidingPanel` only tracks the
1777
+ // plan; open documents/workstreams keep the panel visible on their own, so without this the
1778
+ // toggle can't hide the panel while a document is open. Explicit reveals (opening an artifact
1779
+ // or document) clear it again.
1780
+ const [rightPanelManuallyClosed, setRightPanelManuallyClosed] = useState(false);
1700
1781
 
1701
1782
  const isRightPanelVisible =
1702
1783
  showRightPanelProp &&
1784
+ !rightPanelManuallyClosed &&
1703
1785
  (showSlidingPanel ||
1704
1786
  isDocPanelOpen ||
1705
1787
  (!hideWorkstreamTabs && panelWorkstreams.length > 0) ||
1706
1788
  !!conversationContent ||
1707
1789
  conversationTab);
1708
1790
 
1791
+ // A newly opened document should reveal the panel even if the user had manually collapsed it.
1792
+ const previousDocPanelOpenRef = useRef(isDocPanelOpen);
1793
+ useEffect(() => {
1794
+ if (isDocPanelOpen && !previousDocPanelOpenRef.current) {
1795
+ setRightPanelManuallyClosed(false);
1796
+ }
1797
+ previousDocPanelOpenRef.current = isDocPanelOpen;
1798
+ }, [isDocPanelOpen]);
1799
+
1800
+ const handleTogglePlanPanel = useCallback(() => {
1801
+ if (isRightPanelVisible) {
1802
+ setRightPanelManuallyClosed(true);
1803
+ setShowSlidingPanel(false);
1804
+ } else {
1805
+ setRightPanelManuallyClosed(false);
1806
+ setShowSlidingPanel(true);
1807
+ sessionStorage.setItem('plan-panel-shown', 'true');
1808
+ }
1809
+ }, [isRightPanelVisible, setShowSlidingPanel]);
1810
+
1709
1811
  useEffect(() => {
1710
1812
  if (!isRightPanelVisible && isRightPanelResizing) {
1711
1813
  setIsRightPanelResizing(false);
@@ -1747,10 +1849,44 @@ function ModernAgentConversationInner({
1747
1849
  }, [isRightPanelResizing]);
1748
1850
 
1749
1851
  const handleCloseRightPanel = useCallback(() => {
1852
+ setRightPanelManuallyClosed(true);
1750
1853
  setShowSlidingPanel(false);
1751
1854
  handleCloseDocPanel();
1752
1855
  }, [setShowSlidingPanel, handleCloseDocPanel]);
1753
1856
 
1857
+ const handleOpenArtifact = useCallback(
1858
+ (path: string) => {
1859
+ if (!/\.md$/i.test(path)) return;
1860
+ setRightPanelManuallyClosed(false);
1861
+ setSelectedArtifactPath(path);
1862
+ setRightPanelTab('artifacts');
1863
+ setShowSlidingPanel(true);
1864
+ },
1865
+ [setShowSlidingPanel],
1866
+ );
1867
+
1868
+ // The `display_artifact` tool emits a `display_artifact` stream event asking the UI
1869
+ // to reveal a text artifact in the editor. Act on the latest such event, once per
1870
+ // distinct occurrence so the user can still close the panel without it snapping back.
1871
+ const displayedArtifactMarkerRef = useRef<string | null>(null);
1872
+ useEffect(() => {
1873
+ let target: string | undefined;
1874
+ let marker: string | undefined;
1875
+ for (const message of messages) {
1876
+ const details = message.details as Record<string, unknown> | undefined;
1877
+ if (details?.event_class === 'display_artifact' && typeof details.path === 'string') {
1878
+ target = details.path;
1879
+ marker = `${message.timestamp ?? ''}:${details.path}`;
1880
+ }
1881
+ }
1882
+ if (!target || !marker || marker === displayedArtifactMarkerRef.current) return;
1883
+ displayedArtifactMarkerRef.current = marker;
1884
+ setRightPanelManuallyClosed(false);
1885
+ setSelectedArtifactPath(target);
1886
+ setRightPanelTab('artifacts');
1887
+ setShowSlidingPanel(true);
1888
+ }, [messages, setShowSlidingPanel]);
1889
+
1754
1890
  // Default StoreLinkComponent that opens documents in the panel
1755
1891
  const internalStoreLinkComponent = useCallback(
1756
1892
  ({ href, documentId, children }: { href: string; documentId: string; children: React.ReactNode }) => (
@@ -1801,6 +1937,7 @@ function ModernAgentConversationInner({
1801
1937
 
1802
1938
  useEffect(() => {
1803
1939
  void agentRunId;
1940
+ setSelectedArtifactPath(null);
1804
1941
  workstreamFetchFailedRef.current = false;
1805
1942
  setIsWorkstreamQueryUnavailable(false);
1806
1943
  setQueriedActiveWorkstreams([]);
@@ -1978,7 +2115,12 @@ function ModernAgentConversationInner({
1978
2115
  type: AgentMessageType.QUESTION,
1979
2116
  message: messageContent,
1980
2117
  workstream_id: 'main',
1981
- details: { _optimistic: true, _messageId: messageId, _deliveryStatus: 'sending' },
2118
+ details: {
2119
+ _optimistic: true,
2120
+ _messageId: messageId,
2121
+ _deliveryStatus: 'sending',
2122
+ ...(inputMetadata?.editing_action ? { editing_action: inputMetadata.editing_action } : {}),
2123
+ },
1982
2124
  };
1983
2125
 
1984
2126
  addOptimisticMessage(optimisticMessage);
@@ -2049,6 +2191,13 @@ function ModernAgentConversationInner({
2049
2191
  ],
2050
2192
  );
2051
2193
 
2194
+ useEffect(() => {
2195
+ if (sendMessageRef) sendMessageRef.current = handleSendMessage;
2196
+ return () => {
2197
+ if (sendMessageRef?.current === handleSendMessage) sendMessageRef.current = null;
2198
+ };
2199
+ }, [handleSendMessage, sendMessageRef]);
2200
+
2052
2201
  // After the user connects an MCP server requested via request_mcp_connection, flag the
2053
2202
  // conversation for tool re-discovery and resume it with a confirmation message so the agent
2054
2203
  // continues automatically with the newly-available tools.
@@ -2382,6 +2531,21 @@ function ModernAgentConversationInner({
2382
2531
  return false;
2383
2532
  }).length;
2384
2533
  }, [messages]);
2534
+ const selectedArtifactRefresh = useMemo(() => {
2535
+ if (!selectedArtifactPath) return { key: artifactRefreshKey, details: undefined };
2536
+
2537
+ let key = 0;
2538
+ let details: Record<string, unknown> | undefined;
2539
+ for (const message of messages) {
2540
+ const candidate = message.details as Record<string, unknown> | undefined;
2541
+ if (!isArtifactRefreshEvent(candidate, selectedArtifactPath)) continue;
2542
+ key++;
2543
+ details = candidate;
2544
+ }
2545
+ return { key, details };
2546
+ }, [artifactRefreshKey, messages, selectedArtifactPath]);
2547
+ const canCollaborateWithArtifacts =
2548
+ interactive && isPlaybackLive && effectiveWorkflowStatus?.toUpperCase() === 'RUNNING';
2385
2549
 
2386
2550
  // PERFORMANCE: Memoize taskLabels to prevent AllMessagesMixed re-renders
2387
2551
  const taskLabels = useMemo(
@@ -2405,7 +2569,7 @@ function ModernAgentConversationInner({
2405
2569
  workflowRunId={workflowRunId || ''}
2406
2570
  viewMode={viewMode}
2407
2571
  onViewModeChange={handleViewModeChange}
2408
- showPlanPanel={showRightPanelProp && showSlidingPanel}
2572
+ showPlanPanel={isRightPanelVisible}
2409
2573
  hasPlan={showRightPanelProp && plans.length > 0}
2410
2574
  showPlanButton={showRightPanelProp && !conversationTab}
2411
2575
  onTogglePlanPanel={handleTogglePlanPanel}
@@ -2479,6 +2643,7 @@ function ModernAgentConversationInner({
2479
2643
  taskLabels={taskLabels}
2480
2644
  streamingMessages={displayedStreamingMessages}
2481
2645
  onSendMessage={isPlaybackLive ? handleSendMessage : undefined}
2646
+ onOpenArtifact={showArtifacts ? handleOpenArtifact : undefined}
2482
2647
  messageItemClassNames={messageItemClassNames}
2483
2648
  messageStyleOverrides={messageStyleOverrides}
2484
2649
  toolCallGroupClassNames={toolCallGroupClassNames}
@@ -2551,56 +2716,59 @@ function ModernAgentConversationInner({
2551
2716
  )
2552
2717
  ) : (
2553
2718
  (showInput || canContinueConversation) && (
2554
- <MessageInput
2555
- onSend={handleSendMessage}
2556
- onStop={allowWorkflowControl ? handleStopWorkflow : undefined}
2557
- approvalModeSlot={
2558
- interactive && toolApprovalMode ? (
2559
- <AgentApprovalModeSelector
2560
- mode={toolApprovalMode}
2561
- onChange={handleToolApprovalModeChange}
2562
- disabled={
2563
- !isPlaybackLive || isWorkflowTerminal || !allowWorkflowControl
2564
- }
2719
+ <>
2720
+ {composerContext}
2721
+ <MessageInput
2722
+ onSend={handleSendMessage}
2723
+ onStop={allowWorkflowControl ? handleStopWorkflow : undefined}
2724
+ approvalModeSlot={
2725
+ interactive && toolApprovalMode ? (
2726
+ <AgentApprovalModeSelector
2727
+ mode={toolApprovalMode}
2728
+ onChange={handleToolApprovalModeChange}
2729
+ disabled={
2730
+ !isPlaybackLive || isWorkflowTerminal || !allowWorkflowControl
2731
+ }
2732
+ />
2733
+ ) : undefined
2734
+ }
2735
+ mcpSlot={
2736
+ <McpConnectionsActionMenu
2737
+ disabledCollections={mcpDisabled}
2738
+ onChange={handleMcpDisabledChange}
2739
+ onConnectionChange={handleMcpConnectionChange}
2565
2740
  />
2566
- ) : undefined
2567
- }
2568
- mcpSlot={
2569
- <McpConnectionsActionMenu
2570
- disabledCollections={mcpDisabled}
2571
- onChange={handleMcpDisabledChange}
2572
- onConnectionChange={handleMcpConnectionChange}
2573
- />
2574
- }
2575
- disabled={isUploading || !isPlaybackLive}
2576
- isSending={isSending || isUploading}
2577
- isStopping={isStopping}
2578
- isStreaming={!effectiveIsCompleted}
2579
- isCompleted={effectiveIsCompleted}
2580
- contextWindowUsage={canCompactContext ? contextWindowUsage : undefined}
2581
- onCompactContext={canCompactContext ? handleCompactContext : undefined}
2582
- isCompactingContext={isCompactingContext}
2583
- activeTaskCount={activeTaskCount}
2584
- activeWorkstreams={composerActiveWorkstreams}
2585
- placeholder={composerPlaceholder}
2586
- onFilesSelected={canUploadFiles ? handleFileUpload : undefined}
2587
- uploadedFiles={uploadedFiles}
2588
- onRemoveFile={onRemoveFile}
2589
- onRemoveProcessingFile={handleRemoveProcessingFile}
2590
- acceptedFileTypes={acceptedFileTypes}
2591
- maxFiles={maxFiles}
2592
- processingFiles={processingFiles}
2593
- artifactRunId={agentRunId}
2594
- hasProcessingFiles={hasProcessingFiles}
2595
- renderDocumentSearch={renderDocumentSearch}
2596
- selectedDocuments={selectedDocuments}
2597
- onRemoveDocument={onRemoveDocument}
2598
- hideObjectLinking={hideObjectLinking}
2599
- hideFileUpload={!canUploadFiles}
2600
- disableDropZone={canUploadFiles}
2601
- className={inputContainerClassName}
2602
- inputClassName={inputClassName}
2603
- />
2741
+ }
2742
+ disabled={isUploading || !isPlaybackLive}
2743
+ isSending={isSending || isUploading}
2744
+ isStopping={isStopping}
2745
+ isStreaming={!effectiveIsCompleted}
2746
+ isCompleted={effectiveIsCompleted}
2747
+ contextWindowUsage={canCompactContext ? contextWindowUsage : undefined}
2748
+ onCompactContext={canCompactContext ? handleCompactContext : undefined}
2749
+ isCompactingContext={isCompactingContext}
2750
+ activeTaskCount={activeTaskCount}
2751
+ activeWorkstreams={composerActiveWorkstreams}
2752
+ placeholder={composerPlaceholder}
2753
+ onFilesSelected={canUploadFiles ? handleFileUpload : undefined}
2754
+ uploadedFiles={uploadedFiles}
2755
+ onRemoveFile={onRemoveFile}
2756
+ onRemoveProcessingFile={handleRemoveProcessingFile}
2757
+ acceptedFileTypes={acceptedFileTypes}
2758
+ maxFiles={maxFiles}
2759
+ processingFiles={processingFiles}
2760
+ artifactRunId={agentRunId}
2761
+ hasProcessingFiles={hasProcessingFiles}
2762
+ renderDocumentSearch={renderDocumentSearch}
2763
+ selectedDocuments={selectedDocuments}
2764
+ onRemoveDocument={onRemoveDocument}
2765
+ hideObjectLinking={hideObjectLinking}
2766
+ hideFileUpload={!canUploadFiles}
2767
+ disableDropZone={canUploadFiles}
2768
+ className={inputContainerClassName}
2769
+ inputClassName={inputClassName}
2770
+ />
2771
+ </>
2604
2772
  )
2605
2773
  )}
2606
2774
  </div>
@@ -2717,7 +2885,11 @@ function ModernAgentConversationInner({
2717
2885
  processingFiles={processingFilesProp ?? processingFiles}
2718
2886
  // Artifacts
2719
2887
  showArtifacts={showArtifacts}
2720
- artifactRefreshKey={artifactRefreshKey}
2888
+ artifactRefreshKey={selectedArtifactRefresh.key}
2889
+ artifactRefreshDetails={selectedArtifactRefresh.details}
2890
+ selectedArtifactPath={selectedArtifactPath}
2891
+ onSelectedArtifactPathChange={setSelectedArtifactPath}
2892
+ onSendMessage={canCollaborateWithArtifacts ? handleSendMessage : undefined}
2721
2893
  // Messages (for workstreams tab context)
2722
2894
  messages={messages}
2723
2895
  // Payload content
@@ -0,0 +1,79 @@
1
+ // @vitest-environment jsdom
2
+ import { cleanup, render, screen } from '@testing-library/react';
3
+ import type React from 'react';
4
+ import { afterEach, describe, expect, it, vi } from 'vitest';
5
+ import { createAgentMarkdownAnchor } from './AgentMarkdownAnchor';
6
+
7
+ afterEach(() => cleanup());
8
+
9
+ describe('createAgentMarkdownAnchor', () => {
10
+ it.each([
11
+ 'https://example.com/store/objects/doc-1?view=full#section',
12
+ '//example.com/store/collections/col-1?view=full#section',
13
+ ])('keeps external resource-shaped URLs external: %s', (href) => {
14
+ const StoreLinkComponent = vi.fn(() => null);
15
+ const CollectionLinkComponent = vi.fn(() => null);
16
+ const Anchor = createAgentMarkdownAnchor({ StoreLinkComponent, CollectionLinkComponent });
17
+
18
+ render(<Anchor href={href}>External</Anchor>);
19
+
20
+ expect(screen.getByRole('link', { name: 'External' }).getAttribute('href')).toBe(href);
21
+ expect(screen.getByRole('link', { name: 'External' }).getAttribute('target')).toBe('_blank');
22
+ expect(StoreLinkComponent).not.toHaveBeenCalled();
23
+ expect(CollectionLinkComponent).not.toHaveBeenCalled();
24
+ });
25
+
26
+ it('passes a clean document id and styling to the host document link', () => {
27
+ const StoreLinkComponent = ({
28
+ href,
29
+ documentId,
30
+ className,
31
+ children,
32
+ }: {
33
+ href: string;
34
+ documentId: string;
35
+ className?: string;
36
+ children: React.ReactNode;
37
+ }) => (
38
+ <a href={href} className={className} data-document-id={documentId}>
39
+ {children}
40
+ </a>
41
+ );
42
+ const Anchor = createAgentMarkdownAnchor({
43
+ StoreLinkComponent,
44
+ addStickyParams: (href) => `${href}&a=account-1`,
45
+ });
46
+
47
+ render(
48
+ <Anchor href="/store/objects/doc-1?revision=rev-1#properties" className="resource-link">
49
+ Document
50
+ </Anchor>,
51
+ );
52
+
53
+ const link = screen.getByRole('link', { name: 'Document' });
54
+ expect(link.getAttribute('data-document-id')).toBe('doc-1');
55
+ expect(link.getAttribute('href')).toBe('/store/objects/doc-1?revision=rev-1#properties&a=account-1');
56
+ expect(link.className).toBe('resource-link');
57
+ });
58
+
59
+ it('passes a clean collection id to the host collection link', () => {
60
+ const CollectionLinkComponent = ({
61
+ href,
62
+ collectionId,
63
+ children,
64
+ }: {
65
+ href: string;
66
+ collectionId: string;
67
+ children: React.ReactNode;
68
+ }) => (
69
+ <a href={href} data-collection-id={collectionId}>
70
+ {children}
71
+ </a>
72
+ );
73
+ const Anchor = createAgentMarkdownAnchor({ CollectionLinkComponent });
74
+
75
+ render(<Anchor href="/store/collections/col-1?tab=objects#top">Collection</Anchor>);
76
+
77
+ expect(screen.getByRole('link', { name: 'Collection' }).getAttribute('data-collection-id')).toBe('col-1');
78
+ });
79
+ });