@vertesia/ui 0.80.0-dev-20251118 → 0.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +105 -0
  2. package/lib/esm/core/components/MenuList.js +2 -5
  3. package/lib/esm/core/components/MenuList.js.map +1 -1
  4. package/lib/esm/core/components/MessageBox.js +1 -1
  5. package/lib/esm/core/components/MessageBox.js.map +1 -1
  6. package/lib/esm/core/components/TagsInput.js +194 -0
  7. package/lib/esm/core/components/TagsInput.js.map +1 -0
  8. package/lib/esm/core/components/index.js +2 -1
  9. package/lib/esm/core/components/index.js.map +1 -1
  10. package/lib/esm/core/components/shadcn/dialog.js +16 -2
  11. package/lib/esm/core/components/shadcn/dialog.js.map +1 -1
  12. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js +6 -9
  13. package/lib/esm/core/components/shadcn/filters/filter/SelectFilter.js.map +1 -1
  14. package/lib/esm/core/components/shadcn/filters/filterBar.js +1 -1
  15. package/lib/esm/core/components/shadcn/filters/filterBar.js.map +1 -1
  16. package/lib/esm/core/components/shadcn/popover.js +1 -1
  17. package/lib/esm/core/components/shadcn/popover.js.map +1 -1
  18. package/lib/esm/core/components/shadcn/selectBox.js +23 -5
  19. package/lib/esm/core/components/shadcn/selectBox.js.map +1 -1
  20. package/lib/esm/core/components/shadcn/tabs.js +3 -3
  21. package/lib/esm/core/components/shadcn/tabs.js.map +1 -1
  22. package/lib/esm/env/index.js +4 -1
  23. package/lib/esm/env/index.js.map +1 -1
  24. package/lib/esm/features/agent/chat/AgentChart.js +184 -0
  25. package/lib/esm/features/agent/chat/AgentChart.js.map +1 -0
  26. package/lib/esm/features/agent/chat/ModernAgentConversation.js +87 -10
  27. package/lib/esm/features/agent/chat/ModernAgentConversation.js.map +1 -1
  28. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +6 -2
  29. package/lib/esm/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  30. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js +4 -4
  31. package/lib/esm/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  32. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js +4 -1
  33. package/lib/esm/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.js.map +1 -1
  34. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js +12 -4
  35. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  36. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js +60 -56
  37. package/lib/esm/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  38. package/lib/esm/features/agent/chat/index.js +1 -0
  39. package/lib/esm/features/agent/chat/index.js.map +1 -1
  40. package/lib/esm/features/agent/createChartTool.js +354 -0
  41. package/lib/esm/features/agent/createChartTool.js.map +1 -0
  42. package/lib/esm/features/agent/examples.js +295 -0
  43. package/lib/esm/features/agent/examples.js.map +1 -0
  44. package/lib/esm/features/agent/index.js +2 -0
  45. package/lib/esm/features/agent/index.js.map +1 -1
  46. package/lib/esm/features/agent/visualization.js +165 -0
  47. package/lib/esm/features/agent/visualization.js.map +1 -0
  48. package/lib/esm/features/facets/CollectionsFacetsNav.js +5 -1
  49. package/lib/esm/features/facets/CollectionsFacetsNav.js.map +1 -1
  50. package/lib/esm/features/index.js +1 -0
  51. package/lib/esm/features/index.js.map +1 -1
  52. package/lib/esm/features/layout/GenericPageNavHeader.js +14 -4
  53. package/lib/esm/features/layout/GenericPageNavHeader.js.map +1 -1
  54. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js +268 -0
  55. package/lib/esm/features/magic-pdf/AnnotatedImageSlider.js.map +1 -0
  56. package/lib/esm/features/magic-pdf/DownloadPopover.js +11 -11
  57. package/lib/esm/features/magic-pdf/DownloadPopover.js.map +1 -1
  58. package/lib/esm/features/magic-pdf/ExtractedContentView.js +77 -0
  59. package/lib/esm/features/magic-pdf/ExtractedContentView.js.map +1 -0
  60. package/lib/esm/features/magic-pdf/MagicPdfProvider.js +242 -0
  61. package/lib/esm/features/magic-pdf/MagicPdfProvider.js.map +1 -0
  62. package/lib/esm/features/magic-pdf/MagicPdfView.js +41 -47
  63. package/lib/esm/features/magic-pdf/MagicPdfView.js.map +1 -1
  64. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js +261 -0
  65. package/lib/esm/features/pdf-viewer/PdfPageRenderer.js.map +1 -0
  66. package/lib/esm/features/pdf-viewer/PdfPageSlider.js +276 -0
  67. package/lib/esm/features/pdf-viewer/PdfPageSlider.js.map +1 -0
  68. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js +71 -0
  69. package/lib/esm/features/pdf-viewer/SimplePdfViewer.js.map +1 -0
  70. package/lib/esm/features/pdf-viewer/index.js +4 -0
  71. package/lib/esm/features/pdf-viewer/index.js.map +1 -0
  72. package/lib/esm/features/store/collections/EditCollectionView.js +19 -10
  73. package/lib/esm/features/store/collections/EditCollectionView.js.map +1 -1
  74. package/lib/esm/features/store/collections/SelectCollection.js +104 -39
  75. package/lib/esm/features/store/collections/SelectCollection.js.map +1 -1
  76. package/lib/esm/features/store/collections/SharedPropsEditor.js +39 -0
  77. package/lib/esm/features/store/collections/SharedPropsEditor.js.map +1 -0
  78. package/lib/esm/features/store/collections/SyncMemberHeadsToggle.js +35 -0
  79. package/lib/esm/features/store/collections/SyncMemberHeadsToggle.js.map +1 -0
  80. package/lib/esm/features/store/collections/index.js +2 -0
  81. package/lib/esm/features/store/collections/index.js.map +1 -1
  82. package/lib/esm/features/store/objects/DocumentSearchResults.js +0 -7
  83. package/lib/esm/features/store/objects/DocumentSearchResults.js.map +1 -1
  84. package/lib/esm/features/store/objects/components/ContentOverview.js +273 -83
  85. package/lib/esm/features/store/objects/components/ContentOverview.js.map +1 -1
  86. package/lib/esm/features/store/objects/components/useContentPanelHooks.js +153 -0
  87. package/lib/esm/features/store/objects/components/useContentPanelHooks.js.map +1 -0
  88. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js +3 -3
  89. package/lib/esm/features/store/objects/layout/DocumentTableColumn.js.map +1 -1
  90. package/lib/esm/features/store/objects/layout/renderers.js +13 -0
  91. package/lib/esm/features/store/objects/layout/renderers.js.map +1 -1
  92. package/lib/esm/features/store/objects/upload/useSmartFileUploadProcessing.js +10 -9
  93. package/lib/esm/features/store/objects/upload/useSmartFileUploadProcessing.js.map +1 -1
  94. package/lib/esm/features/utils/index.js +2 -0
  95. package/lib/esm/features/utils/index.js.map +1 -1
  96. package/lib/esm/features/utils/mimeType.js +8 -0
  97. package/lib/esm/features/utils/mimeType.js.map +1 -1
  98. package/lib/esm/features/utils/print.js +181 -0
  99. package/lib/esm/features/utils/print.js.map +1 -0
  100. package/lib/esm/features/utils/workflowStatus.js +43 -0
  101. package/lib/esm/features/utils/workflowStatus.js.map +1 -0
  102. package/lib/esm/router/HistoryNavigator.js +22 -2
  103. package/lib/esm/router/HistoryNavigator.js.map +1 -1
  104. package/lib/esm/session/UserSessionProvider.js +2 -2
  105. package/lib/esm/session/UserSessionProvider.js.map +1 -1
  106. package/lib/esm/shell/apps/AppProjectSelector.js +2 -2
  107. package/lib/esm/shell/apps/AppProjectSelector.js.map +1 -1
  108. package/lib/esm/shell/login/UserInfo.js +2 -1
  109. package/lib/esm/shell/login/UserInfo.js.map +1 -1
  110. package/lib/esm/shell/login/UserSessionMenu.js +7 -1
  111. package/lib/esm/shell/login/UserSessionMenu.js.map +1 -1
  112. package/lib/esm/widgets/form/Form.js +6 -2
  113. package/lib/esm/widgets/form/Form.js.map +1 -1
  114. package/lib/esm/widgets/markdown/MarkdownRenderer.js +226 -4
  115. package/lib/esm/widgets/markdown/MarkdownRenderer.js.map +1 -1
  116. package/lib/esm/widgets/schema-editor/ManagedSchema.js +0 -3
  117. package/lib/esm/widgets/schema-editor/ManagedSchema.js.map +1 -1
  118. package/lib/esm/widgets/schema-editor/json-schema4-utils.js +1 -1
  119. package/lib/esm/widgets/schema-editor/json-schema4-utils.js.map +1 -1
  120. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js +18 -9
  121. package/lib/esm/widgets/xml-viewer/components/XMLViewer.js.map +1 -1
  122. package/lib/esm/widgets/xml-viewer/constants/index.js +10 -0
  123. package/lib/esm/widgets/xml-viewer/constants/index.js.map +1 -1
  124. package/lib/tsconfig.tsbuildinfo +1 -1
  125. package/lib/types/core/components/MessageBox.d.ts.map +1 -1
  126. package/lib/types/core/components/TagsInput.d.ts +16 -0
  127. package/lib/types/core/components/TagsInput.d.ts.map +1 -0
  128. package/lib/types/core/components/index.d.ts +2 -1
  129. package/lib/types/core/components/index.d.ts.map +1 -1
  130. package/lib/types/core/components/shadcn/dialog.d.ts +2 -1
  131. package/lib/types/core/components/shadcn/dialog.d.ts.map +1 -1
  132. package/lib/types/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  133. package/lib/types/core/components/shadcn/popover.d.ts +7 -0
  134. package/lib/types/core/components/shadcn/popover.d.ts.map +1 -1
  135. package/lib/types/core/components/shadcn/selectBox.d.ts +5 -1
  136. package/lib/types/core/components/shadcn/selectBox.d.ts.map +1 -1
  137. package/lib/types/core/components/shadcn/tabs.d.ts +3 -1
  138. package/lib/types/core/components/shadcn/tabs.d.ts.map +1 -1
  139. package/lib/types/env/index.d.ts +2 -0
  140. package/lib/types/env/index.d.ts.map +1 -1
  141. package/lib/types/features/agent/chat/AgentChart.d.ts +48 -0
  142. package/lib/types/features/agent/chat/AgentChart.d.ts.map +1 -0
  143. package/lib/types/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  144. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -2
  145. package/lib/types/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  146. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts +2 -1
  147. package/lib/types/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  148. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts +4 -2
  149. package/lib/types/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.d.ts.map +1 -1
  150. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +2 -4
  151. package/lib/types/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  152. package/lib/types/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  153. package/lib/types/features/agent/chat/index.d.ts +1 -0
  154. package/lib/types/features/agent/chat/index.d.ts.map +1 -1
  155. package/lib/types/features/agent/createChartTool.d.ts +178 -0
  156. package/lib/types/features/agent/createChartTool.d.ts.map +1 -0
  157. package/lib/types/features/agent/examples.d.ts +59 -0
  158. package/lib/types/features/agent/examples.d.ts.map +1 -0
  159. package/lib/types/features/agent/index.d.ts +2 -0
  160. package/lib/types/features/agent/index.d.ts.map +1 -1
  161. package/lib/types/features/agent/visualization.d.ts +95 -0
  162. package/lib/types/features/agent/visualization.d.ts.map +1 -0
  163. package/lib/types/features/facets/CollectionsFacetsNav.d.ts.map +1 -1
  164. package/lib/types/features/index.d.ts +1 -0
  165. package/lib/types/features/index.d.ts.map +1 -1
  166. package/lib/types/features/layout/GenericPageNavHeader.d.ts.map +1 -1
  167. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts +13 -0
  168. package/lib/types/features/magic-pdf/AnnotatedImageSlider.d.ts.map +1 -0
  169. package/lib/types/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  170. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts +8 -0
  171. package/lib/types/features/magic-pdf/ExtractedContentView.d.ts.map +1 -0
  172. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts +58 -0
  173. package/lib/types/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -0
  174. package/lib/types/features/magic-pdf/MagicPdfView.d.ts +1 -1
  175. package/lib/types/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
  176. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts +83 -0
  177. package/lib/types/features/pdf-viewer/PdfPageRenderer.d.ts.map +1 -0
  178. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts +29 -0
  179. package/lib/types/features/pdf-viewer/PdfPageSlider.d.ts.map +1 -0
  180. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts +19 -0
  181. package/lib/types/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -0
  182. package/lib/types/features/pdf-viewer/index.d.ts +4 -0
  183. package/lib/types/features/pdf-viewer/index.d.ts.map +1 -0
  184. package/lib/types/features/store/collections/EditCollectionView.d.ts.map +1 -1
  185. package/lib/types/features/store/collections/SelectCollection.d.ts +2 -1
  186. package/lib/types/features/store/collections/SelectCollection.d.ts.map +1 -1
  187. package/lib/types/features/store/collections/SharedPropsEditor.d.ts +7 -0
  188. package/lib/types/features/store/collections/SharedPropsEditor.d.ts.map +1 -0
  189. package/lib/types/features/store/collections/SyncMemberHeadsToggle.d.ts +7 -0
  190. package/lib/types/features/store/collections/SyncMemberHeadsToggle.d.ts.map +1 -0
  191. package/lib/types/features/store/collections/index.d.ts +2 -0
  192. package/lib/types/features/store/collections/index.d.ts.map +1 -1
  193. package/lib/types/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  194. package/lib/types/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  195. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts +30 -0
  196. package/lib/types/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -0
  197. package/lib/types/features/store/objects/layout/renderers.d.ts.map +1 -1
  198. package/lib/types/features/store/objects/upload/useSmartFileUploadProcessing.d.ts.map +1 -1
  199. package/lib/types/features/utils/index.d.ts +2 -0
  200. package/lib/types/features/utils/index.d.ts.map +1 -1
  201. package/lib/types/features/utils/mimeType.d.ts +1 -0
  202. package/lib/types/features/utils/mimeType.d.ts.map +1 -1
  203. package/lib/types/features/utils/print.d.ts +10 -0
  204. package/lib/types/features/utils/print.d.ts.map +1 -0
  205. package/lib/types/features/utils/workflowStatus.d.ts +10 -0
  206. package/lib/types/features/utils/workflowStatus.d.ts.map +1 -0
  207. package/lib/types/router/HistoryNavigator.d.ts +3 -0
  208. package/lib/types/router/HistoryNavigator.d.ts.map +1 -1
  209. package/lib/types/shell/login/UserInfo.d.ts.map +1 -1
  210. package/lib/types/shell/login/UserSessionMenu.d.ts.map +1 -1
  211. package/lib/types/widgets/form/Form.d.ts.map +1 -1
  212. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts +5 -1
  213. package/lib/types/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  214. package/lib/types/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  215. package/lib/types/widgets/xml-viewer/components/XMLViewer.d.ts.map +1 -1
  216. package/lib/types/widgets/xml-viewer/constants/index.d.ts +10 -0
  217. package/lib/types/widgets/xml-viewer/constants/index.d.ts.map +1 -1
  218. package/lib/vertesia-ui-core.js +1 -1
  219. package/lib/vertesia-ui-core.js.map +1 -1
  220. package/lib/vertesia-ui-env.js +1 -1
  221. package/lib/vertesia-ui-env.js.map +1 -1
  222. package/lib/vertesia-ui-features.js +1 -1
  223. package/lib/vertesia-ui-features.js.map +1 -1
  224. package/lib/vertesia-ui-layout.js +1 -1
  225. package/lib/vertesia-ui-layout.js.map +1 -1
  226. package/lib/vertesia-ui-router.js +1 -1
  227. package/lib/vertesia-ui-router.js.map +1 -1
  228. package/lib/vertesia-ui-session.js +1 -1
  229. package/lib/vertesia-ui-session.js.map +1 -1
  230. package/lib/vertesia-ui-shell.js +1 -1
  231. package/lib/vertesia-ui-shell.js.map +1 -1
  232. package/lib/vertesia-ui-widgets.js +1 -1
  233. package/lib/vertesia-ui-widgets.js.map +1 -1
  234. package/package.json +173 -170
  235. package/src/core/components/MenuList.tsx +3 -6
  236. package/src/core/components/MessageBox.tsx +7 -2
  237. package/src/core/components/SelectBox.tsx +1 -1
  238. package/src/core/components/shadcn/dialog.tsx +19 -1
  239. package/src/core/components/shadcn/filters/filter/SelectFilter.tsx +31 -31
  240. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  241. package/src/core/components/shadcn/selectBox.tsx +32 -6
  242. package/src/core/components/shadcn/tabs.tsx +3 -2
  243. package/src/env/index.ts +6 -1
  244. package/src/features/agent/CHART_INSTRUCTIONS.md +228 -0
  245. package/src/features/agent/chat/AgentChart.tsx +601 -0
  246. package/src/features/agent/chat/ModernAgentConversation.tsx +123 -11
  247. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +8 -2
  248. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +12 -2
  249. package/src/features/agent/chat/ModernAgentOutput/InlineSlidingPlanPanel.tsx +6 -1
  250. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +15 -10
  251. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +122 -87
  252. package/src/features/agent/chat/index.ts +1 -0
  253. package/src/features/agent/createChartTool.ts +364 -0
  254. package/src/features/agent/examples.ts +321 -0
  255. package/src/features/agent/index.ts +2 -0
  256. package/src/features/agent/visualization.ts +227 -0
  257. package/src/features/facets/CollectionsFacetsNav.tsx +5 -1
  258. package/src/features/index.ts +1 -0
  259. package/src/features/layout/GenericPageNavHeader.tsx +15 -4
  260. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +482 -0
  261. package/src/features/magic-pdf/DownloadPopover.tsx +45 -40
  262. package/src/features/magic-pdf/ExtractedContentView.tsx +132 -0
  263. package/src/features/magic-pdf/MagicPdfProvider.tsx +297 -0
  264. package/src/features/magic-pdf/MagicPdfView.tsx +184 -91
  265. package/src/features/pdf-viewer/PdfPageRenderer.tsx +612 -0
  266. package/src/features/pdf-viewer/PdfPageSlider.tsx +473 -0
  267. package/src/features/pdf-viewer/SimplePdfViewer.tsx +142 -0
  268. package/src/features/pdf-viewer/index.ts +3 -0
  269. package/src/features/store/collections/EditCollectionView.tsx +3 -5
  270. package/src/features/store/collections/SharedPropsEditor.tsx +1 -2
  271. package/src/features/store/objects/DocumentSearchResults.tsx +0 -7
  272. package/src/features/store/objects/components/ContentOverview.tsx +677 -210
  273. package/src/features/store/objects/components/useContentPanelHooks.ts +169 -0
  274. package/src/features/store/objects/layout/DocumentTableColumn.tsx +3 -3
  275. package/src/features/store/objects/layout/knowledge.md +1 -0
  276. package/src/features/store/objects/layout/renderers.tsx +25 -0
  277. package/src/features/store/objects/upload/useSmartFileUploadProcessing.ts +1 -3
  278. package/src/features/utils/index.ts +3 -1
  279. package/src/features/utils/mimeType.ts +10 -1
  280. package/src/features/utils/print.ts +189 -0
  281. package/src/features/utils/workflowStatus.ts +44 -0
  282. package/src/router/HistoryNavigator.ts +30 -2
  283. package/src/session/UserSessionProvider.tsx +2 -2
  284. package/src/shell/login/UserInfo.tsx +2 -0
  285. package/src/shell/login/UserSessionMenu.tsx +12 -1
  286. package/src/widgets/form/Form.tsx +8 -3
  287. package/src/widgets/markdown/MarkdownRenderer.tsx +350 -6
  288. package/src/widgets/schema-editor/ManagedSchema.ts +0 -3
  289. package/src/widgets/schema-editor/json-schema4-utils.ts +1 -1
  290. package/src/widgets/xml-viewer/components/XMLViewer.tsx +22 -10
  291. package/src/widgets/xml-viewer/constants/index.ts +11 -0
  292. package/lib/esm/features/magic-pdf/PageSlider.js +0 -70
  293. package/lib/esm/features/magic-pdf/PageSlider.js.map +0 -1
  294. package/lib/esm/features/magic-pdf/PdfPageProvider.js +0 -188
  295. package/lib/esm/features/magic-pdf/PdfPageProvider.js.map +0 -1
  296. package/lib/esm/features/magic-pdf/TextPageView.js +0 -62
  297. package/lib/esm/features/magic-pdf/TextPageView.js.map +0 -1
  298. package/lib/esm/features/magic-pdf/useResizeOnDrag.js +0 -34
  299. package/lib/esm/features/magic-pdf/useResizeOnDrag.js.map +0 -1
  300. package/lib/types/features/magic-pdf/PageSlider.d.ts +0 -9
  301. package/lib/types/features/magic-pdf/PageSlider.d.ts.map +0 -1
  302. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts +0 -39
  303. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts.map +0 -1
  304. package/lib/types/features/magic-pdf/TextPageView.d.ts +0 -8
  305. package/lib/types/features/magic-pdf/TextPageView.d.ts.map +0 -1
  306. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts +0 -9
  307. package/lib/types/features/magic-pdf/useResizeOnDrag.d.ts.map +0 -1
  308. package/src/features/magic-pdf/PageSlider.tsx +0 -142
  309. package/src/features/magic-pdf/PdfPageProvider.tsx +0 -310
  310. package/src/features/magic-pdf/TextPageView.tsx +0 -91
  311. package/src/features/magic-pdf/useResizeOnDrag.ts +0 -42
@@ -3,7 +3,7 @@ import { Bot, Cpu, SendIcon, XIcon } from "lucide-react";
3
3
  import { useUserSession } from "@vertesia/ui/session";
4
4
  import { AsyncExecutionResult, VertesiaClient } from "@vertesia/client";
5
5
  import { AgentMessage, AgentMessageType, Plan, UserInputSignal } from "@vertesia/common";
6
- import { Button, MessageBox, Spinner, useToast } from "@vertesia/ui/core";
6
+ import { Button, MessageBox, Spinner, useToast, VModal, VModalBody, VModalFooter, VModalTitle } from "@vertesia/ui/core";
7
7
 
8
8
  import { AnimatedThinkingDots, PulsatingCircle } from "./AnimatedThinkingDots";
9
9
  import AllMessagesMixed from "./ModernAgentOutput/AllMessagesMixed";
@@ -17,6 +17,50 @@ type StartWorkflowFn = (
17
17
  initialMessage?: string,
18
18
  ) => Promise<{ run_id: string; workflow_id: string } | undefined>;
19
19
 
20
+ function printElementToPdf(sourceElement: HTMLElement, title: string): boolean {
21
+ if (typeof window === "undefined" || typeof document === "undefined") {
22
+ return false;
23
+ }
24
+
25
+ // Use a hidden iframe to avoid opening a new window
26
+ const iframe = document.createElement("iframe");
27
+ iframe.style.position = "fixed";
28
+ iframe.style.right = "0";
29
+ iframe.style.bottom = "0";
30
+ iframe.style.width = "0";
31
+ iframe.style.height = "0";
32
+ iframe.style.border = "0";
33
+ iframe.style.visibility = "hidden";
34
+ document.body.appendChild(iframe);
35
+
36
+ const iframeWindow = iframe.contentWindow;
37
+ if (!iframeWindow) {
38
+ iframe.parentNode?.removeChild(iframe);
39
+ return false;
40
+ }
41
+
42
+ const doc = iframeWindow.document;
43
+ doc.open();
44
+ doc.write(`<!doctype html><html><head><title>${title}</title></head><body></body></html>`);
45
+ doc.close();
46
+ doc.title = title;
47
+
48
+ const styles = document.querySelectorAll<HTMLLinkElement | HTMLStyleElement>("link[rel=\"stylesheet\"], style");
49
+ styles.forEach((node) => {
50
+ doc.head.appendChild(node.cloneNode(true));
51
+ });
52
+
53
+ doc.body.innerHTML = sourceElement.innerHTML;
54
+ iframeWindow.focus();
55
+ iframeWindow.print();
56
+
57
+ setTimeout(() => {
58
+ iframe.parentNode?.removeChild(iframe);
59
+ }, 1000);
60
+
61
+ return true;
62
+ }
63
+
20
64
  interface ModernAgentConversationProps {
21
65
  run?: AsyncExecutionResult | { workflow_id: string; run_id: string };
22
66
  title?: string;
@@ -248,9 +292,9 @@ function ModernAgentConversationInner({
248
292
  }: ModernAgentConversationProps & { run: AsyncExecutionResult }) {
249
293
  const { client } = useUserSession();
250
294
  const bottomRef = useRef<HTMLDivElement | null>(null);
295
+ const conversationRef = useRef<HTMLDivElement | null>(null);
251
296
  const [messages, setMessages] = useState<AgentMessage[]>([]);
252
297
  const [isCompleted, setIsCompleted] = useState(false);
253
- const [inputValue, setInputValue] = useState<string>("");
254
298
  const [isSending, setIsSending] = useState(false);
255
299
  const [viewMode, setViewMode] = useState<"stacked" | "sliding">("sliding");
256
300
  const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(!isModal);
@@ -486,16 +530,15 @@ function ModernAgentConversationInner({
486
530
  }, [messages, plans, activePlanIndex]);
487
531
 
488
532
  // Send a message to the agent
489
- const handleSendMessage = () => {
490
- const message = inputValue.trim();
491
- if (!message || isSending) return;
533
+ const handleSendMessage = (message: string) => {
534
+ const trimmed = message.trim();
535
+ if (!trimmed || isSending) return;
492
536
 
493
537
  setIsSending(true);
494
- setInputValue("");
495
538
 
496
539
  client.store.workflows
497
540
  .sendSignal(run.workflowId, run.runId, "UserInput", {
498
- message,
541
+ message: trimmed,
499
542
  } as UserInputSignal)
500
543
  .then(() => {
501
544
  setIsCompleted(false);
@@ -583,12 +626,63 @@ function ModernAgentConversationInner({
583
626
  });
584
627
  };
585
628
 
629
+ const [isPdfModalOpen, setIsPdfModalOpen] = useState(false);
630
+
631
+ const exportConversationPdf = () => {
632
+ if (!conversationRef.current) {
633
+ toast({
634
+ status: "error",
635
+ title: "PDF export failed",
636
+ description: "No conversation content available to export",
637
+ duration: 3000,
638
+ });
639
+ return;
640
+ }
641
+ setIsPdfModalOpen(true);
642
+ };
643
+
644
+ const handleConfirmExportPdf = () => {
645
+ if (!conversationRef.current) {
646
+ toast({
647
+ status: "error",
648
+ title: "PDF export failed",
649
+ description: "No conversation content available to export",
650
+ duration: 3000,
651
+ });
652
+ return;
653
+ }
654
+
655
+ const pdfTitle = `${actualTitle} - ${run.runId}`;
656
+ const success = printElementToPdf(conversationRef.current, pdfTitle);
657
+
658
+ if (!success) {
659
+ toast({
660
+ status: "error",
661
+ title: "PDF export failed",
662
+ description: "Unable to open print preview",
663
+ duration: 4000,
664
+ });
665
+ return;
666
+ }
667
+
668
+ toast({
669
+ status: "success",
670
+ title: "PDF export ready",
671
+ description: "Use your browser's Print dialog to save as PDF",
672
+ duration: 4000,
673
+ });
674
+ setIsPdfModalOpen(false);
675
+ };
676
+
586
677
  return (
587
678
  <div className="flex gap-2 h-full">
588
679
  {/* Conversation Area - responsive width based on panel visibility */}
589
- <div className={`flex flex-col h-full min-h-0 border-0 ${
680
+ <div
681
+ ref={conversationRef}
682
+ className={`flex flex-col h-full min-h-0 border-0 ${
590
683
  showSlidingPanel ? 'lg:w-2/3 flex-1' : `flex-1 mx-auto ${!isModal ? 'max-w-4xl' : ''}`
591
- }`}>
684
+ }`}
685
+ >
592
686
  <Header
593
687
  title={actualTitle}
594
688
  isCompleted={isCompleted}
@@ -609,6 +703,7 @@ function ModernAgentConversationInner({
609
703
  onDownload={downloadConversation}
610
704
  onCopyRunId={copyRunId}
611
705
  resetWorkflow={resetWorkflow}
706
+ onExportPdf={exportConversationPdf}
612
707
  />
613
708
 
614
709
  {messages.length === 0 && !isCompleted ? (
@@ -664,8 +759,6 @@ function ModernAgentConversationInner({
664
759
  </MessageBox>
665
760
  ) : showInput && (
666
761
  <MessageInput
667
- value={inputValue}
668
- onChange={setInputValue}
669
762
  onSend={handleSendMessage}
670
763
  disabled={false}
671
764
  isSending={isSending}
@@ -690,6 +783,25 @@ function ModernAgentConversationInner({
690
783
  />
691
784
  </div>
692
785
  )}
786
+ <VModal isOpen={isPdfModalOpen} onClose={() => setIsPdfModalOpen(false)}>
787
+ <VModalTitle>Export conversation as PDF</VModalTitle>
788
+ <VModalBody>
789
+ <p className="mb-2">
790
+ This will open your browser&apos;s print dialog with the current conversation.
791
+ </p>
792
+ <p className="text-sm text-muted">
793
+ To save a PDF, choose &quot;Save as PDF&quot; or a similar option in the print dialog.
794
+ </p>
795
+ </VModalBody>
796
+ <VModalFooter align="right">
797
+ <Button variant="ghost" size="sm" onClick={() => setIsPdfModalOpen(false)}>
798
+ Cancel
799
+ </Button>
800
+ <Button size="sm" onClick={handleConfirmExportPdf}>
801
+ Open print dialog
802
+ </Button>
803
+ </VModalFooter>
804
+ </VModal>
693
805
  </div>
694
806
  );
695
807
  }
@@ -19,7 +19,7 @@ interface AllMessagesMixedProps {
19
19
  taskLabels?: Map<string, string>; // Maps task IDs to more descriptive labels
20
20
  }
21
21
 
22
- export default function AllMessagesMixed({
22
+ function AllMessagesMixedComponent({
23
23
  messages,
24
24
  bottomRef,
25
25
  viewMode = 'stacked',
@@ -167,11 +167,13 @@ export default function AllMessagesMixed({
167
167
  <>
168
168
  {/* Get all messages to display in sliding view */}
169
169
  {(() => {
170
- // First get all permanent messages (ANSWER, QUESTION, COMPLETE, REQUEST_INPUT, TERMINATED)
170
+ // First get all permanent messages (ANSWER, QUESTION, COMPLETE, REQUEST_INPUT, IDLE, TERMINATED)
171
171
  const permanentMessages = displayMessages.filter(msg =>
172
172
  msg.type === AgentMessageType.ANSWER ||
173
173
  msg.type === AgentMessageType.QUESTION ||
174
174
  msg.type === AgentMessageType.COMPLETE ||
175
+ msg.type === AgentMessageType.IDLE ||
176
+ msg.type === AgentMessageType.REQUEST_INPUT ||
175
177
  msg.type === AgentMessageType.TERMINATED
176
178
  );
177
179
 
@@ -225,3 +227,7 @@ export default function AllMessagesMixed({
225
227
  </div>
226
228
  );
227
229
  }
230
+
231
+ const AllMessagesMixed = React.memo(AllMessagesMixedComponent);
232
+
233
+ export default AllMessagesMixed;
@@ -19,6 +19,7 @@ interface HeaderProps {
19
19
  onDownload?: () => void;
20
20
  onCopyRunId?: () => void;
21
21
  resetWorkflow?: () => void;
22
+ onExportPdf?: () => void;
22
23
  }
23
24
 
24
25
  export default function Header({
@@ -33,7 +34,8 @@ export default function Header({
33
34
  onTogglePlanPanel,
34
35
  onDownload,
35
36
  onCopyRunId,
36
- resetWorkflow
37
+ resetWorkflow,
38
+ onExportPdf,
37
39
  }: HeaderProps) {
38
40
  return (
39
41
  <PayloadBuilderProvider>
@@ -84,6 +86,7 @@ export default function Header({
84
86
  onDownload={onDownload}
85
87
  onCopyRunId={onCopyRunId}
86
88
  resetWorkflow={resetWorkflow}
89
+ onExportPdf={onExportPdf}
87
90
  />
88
91
  {onClose && !isModal && (
89
92
  <Button size="xs" variant="ghost" onClick={onClose}>
@@ -102,7 +105,8 @@ function MoreDropdown({
102
105
  onClose,
103
106
  onDownload,
104
107
  onCopyRunId,
105
- resetWorkflow
108
+ resetWorkflow,
109
+ onExportPdf,
106
110
  }: {
107
111
  run: AsyncExecutionResult;
108
112
  isModal: boolean;
@@ -110,6 +114,7 @@ function MoreDropdown({
110
114
  onDownload?: () => void;
111
115
  onCopyRunId?: () => void;
112
116
  resetWorkflow?: () => void;
117
+ onExportPdf?: () => void;
113
118
  }) {
114
119
  const toast = useToast();
115
120
  const { client } = useUserSession();
@@ -191,6 +196,11 @@ function MoreDropdown({
191
196
  <DownloadCloudIcon className="size-3.5 mr-2 text-muted" /> Download
192
197
  Conversation
193
198
  </CommandItem>
199
+ {onExportPdf && (
200
+ <CommandItem className="text-xs" onSelect={onExportPdf}>
201
+ <DownloadCloudIcon className="size-3.5 mr-2 text-muted" /> Export as PDF
202
+ </CommandItem>
203
+ )}
194
204
  {onClose && isModal && (
195
205
  <CommandItem className="text-xs" onSelect={onClose}>
196
206
  <XIcon className="size-3.5 mr-2 text-muted" /> Close
@@ -1,6 +1,7 @@
1
1
  import { Plan } from "@vertesia/common";
2
2
  import { Badge, Button } from "@vertesia/ui/core";
3
3
  import { AlertCircle, CheckCircle, Circle, Clock, X } from "lucide-react";
4
+ import React from "react";
4
5
 
5
6
  interface InlinePlanPanelProps {
6
7
  plan: Plan;
@@ -12,7 +13,7 @@ interface InlinePlanPanelProps {
12
13
  onChangePlan?: (index: number) => void;
13
14
  }
14
15
 
15
- export default function InlineSlidingPlanPanel({
16
+ function InlineSlidingPlanPanelComponent({
16
17
  plan,
17
18
  workstreamStatus,
18
19
  isOpen,
@@ -264,3 +265,7 @@ export default function InlineSlidingPlanPanel({
264
265
  </div>
265
266
  );
266
267
  }
268
+
269
+ const InlineSlidingPlanPanel = React.memo(InlineSlidingPlanPanelComponent);
270
+
271
+ export default InlineSlidingPlanPanel;
@@ -4,9 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
4
4
  import { SelectDocument } from "../../../store";
5
5
 
6
6
  interface MessageInputProps {
7
- value: string;
8
- onChange: (v: string) => void;
9
- onSend: () => void;
7
+ onSend: (message: string) => void;
10
8
  disabled?: boolean;
11
9
  isSending?: boolean;
12
10
  isCompleted?: boolean;
@@ -15,8 +13,6 @@ interface MessageInputProps {
15
13
  }
16
14
 
17
15
  export default function MessageInput({
18
- value,
19
- onChange,
20
16
  onSend,
21
17
  disabled = false,
22
18
  isSending = false,
@@ -25,16 +21,25 @@ export default function MessageInput({
25
21
  placeholder = "Type your message..."
26
22
  }: MessageInputProps) {
27
23
  const ref = useRef<HTMLInputElement | null>(null);
24
+ const [value, setValue] = useState("");
28
25
  const [isObjectModalOpen, setIsObjectModalOpen] = useState(false);
29
26
 
30
27
  useEffect(() => {
31
28
  if (!disabled && isCompleted) ref.current?.focus();
32
29
  }, [disabled, isCompleted]);
33
30
 
31
+ const handleSend = () => {
32
+ const message = value.trim();
33
+ if (!message || disabled || isSending) return;
34
+
35
+ onSend(message);
36
+ setValue("");
37
+ };
38
+
34
39
  const keyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
35
40
  if (e.key === "Enter" && !e.shiftKey) {
36
41
  e.preventDefault();
37
- onSend();
42
+ handleSend();
38
43
  }
39
44
  };
40
45
 
@@ -50,7 +55,7 @@ export default function MessageInput({
50
55
  const newValue = currentValue.substring(0, cursorPos) + markdownLink + currentValue.substring(cursorPos);
51
56
 
52
57
  // Update the input value
53
- onChange(newValue);
58
+ setValue(newValue);
54
59
 
55
60
  // Close the modal
56
61
  setIsObjectModalOpen(false);
@@ -74,7 +79,7 @@ export default function MessageInput({
74
79
  ref={ref}
75
80
  value={value}
76
81
  onKeyDown={keyDown}
77
- onChange={onChange}
82
+ onChange={setValue}
78
83
  disabled={disabled || isSending}
79
84
  placeholder={placeholder}
80
85
  className="pr-12 py-2.5"
@@ -90,7 +95,7 @@ export default function MessageInput({
90
95
  </Button>
91
96
  </div>
92
97
  <Button
93
- onClick={onSend}
98
+ onClick={handleSend}
94
99
  disabled={disabled || isSending || !value.trim()}
95
100
  className="px-4 py-2.5"
96
101
  >
@@ -122,4 +127,4 @@ export default function MessageInput({
122
127
  </VModal>
123
128
  </div>
124
129
  );
125
- }
130
+ }
@@ -2,11 +2,10 @@ import { AgentMessage, AgentMessageType } from "@vertesia/common";
2
2
  import { Badge, Button, useToast } from "@vertesia/ui/core";
3
3
  import { NavLink } from "@vertesia/ui/router";
4
4
  import { useUserSession } from "@vertesia/ui/session";
5
+ import { MarkdownRenderer } from "@vertesia/ui/widgets";
5
6
  import dayjs from "dayjs";
6
7
  import { AlertCircle, Bot, CheckCircle, Clock, CopyIcon, Info, MessageSquare, User } from "lucide-react";
7
8
  import React, { useEffect, useState } from "react";
8
- import Markdown from "react-markdown";
9
- import remarkGfm from "remark-gfm";
10
9
  import { AnimatedThinkingDots, PulsatingCircle } from "../AnimatedThinkingDots";
11
10
  import { ThinkingMessages } from "../WaitingMessages";
12
11
  import { getWorkstreamId } from "./utils";
@@ -100,46 +99,17 @@ export default function MessageItem({ message, showPulsatingCircle = false }: Me
100
99
 
101
100
  const messageStyles = getMessageStyles();
102
101
 
103
- // Convert links in the content (now async to handle image URLs)
102
+ // Convert links in the content.
103
+ // Special schemes like store:, collection:, image:, and artifact:
104
+ // are now handled centrally in MarkdownRenderer, so this function
105
+ // only preserves the async shape for backwards compatibility.
104
106
  const convertLinks = async (content: string | object): Promise<string | object> => {
105
107
  // If content is not a string, return it as is
106
108
  if (typeof content !== "string") {
107
109
  return content;
108
110
  }
109
111
 
110
- let processedContent = content;
111
-
112
- // First, handle store and collection links
113
- processedContent = processedContent.replace(/\[([^\]]+)\]\((store|collection):([a-f\d]{24})\)/gi, (_, text, type, id) => {
114
- const path = type === 'store' ? 'objects' : 'collections';
115
- return `[${text}](/store/${path}/${id})`;
116
- });
117
-
118
- // Then, handle image links by finding all image:<gcspath> patterns
119
- const imageRegex = /!\[([^\]]*)\]\(image:([^)]+)\)/g;
120
- const imageMatches = Array.from(processedContent.matchAll(imageRegex));
121
-
122
- // Process all image URLs in parallel
123
- const imageReplacements = await Promise.all(
124
- imageMatches.map(async (match) => {
125
- const [fullMatch, altText, gcsPath] = match;
126
- try {
127
- const response = await client.files.getDownloadUrl(gcsPath);
128
- return { fullMatch, replacement: `![${altText}](${response.url})` };
129
- } catch (error) {
130
- console.error(`Failed to get download URL for image: ${gcsPath}`, error);
131
- // Return original on error
132
- return { fullMatch, replacement: fullMatch };
133
- }
134
- })
135
- );
136
-
137
- // Apply all replacements
138
- for (const { fullMatch, replacement } of imageReplacements) {
139
- processedContent = processedContent.replace(fullMatch, replacement);
140
- }
141
-
142
- return processedContent;
112
+ return content;
143
113
  };
144
114
 
145
115
  // Get the message content to display with thinking message replacement
@@ -254,10 +224,12 @@ export default function MessageItem({ message, showPulsatingCircle = false }: Me
254
224
  }
255
225
 
256
226
  // Handle string content with markdown - content is already processed
227
+ const runId = (message as any).workflow_run_id as string | undefined;
228
+
257
229
  return (
258
230
  <div className="vprose prose-sm">
259
- <Markdown
260
- remarkPlugins={[remarkGfm]}
231
+ <MarkdownRenderer
232
+ artifactRunId={runId}
261
233
  components={{
262
234
  a: ({ node, ref, ...props }: { node?: any; ref?: any; href?: string; children?: React.ReactNode }) => {
263
235
  const href = props.href || "";
@@ -289,62 +261,78 @@ export default function MessageItem({ message, showPulsatingCircle = false }: Me
289
261
  />
290
262
  );
291
263
  },
292
- code: ({
293
- node,
294
- ref,
295
- className,
296
- children,
297
- ...props
298
- }: {
299
- node?: any;
300
- ref?: any;
301
- className?: string;
302
- children?: React.ReactNode;
303
- }) => {
304
- const match = /language-(\w+)/.exec(className || "");
305
- const isInline = !match;
306
- const language = match ? match[1] : "";
307
-
308
- // Keep only the language indicator logic here, styling moved to CSS
309
- return (
310
- <>
311
- {!isInline && language && (
312
- <div className="code-language-indicator">
313
- {language}
314
- </div>
315
- )}
316
- <code {...props}>
317
- {children}
318
- </code>
319
- </>
320
- );
321
- },
322
- // Remove 'node' and 'ref' from props
323
- p: ({ node, ref, ...props }) => <p {...props} />,
324
- strong: ({ node, ref, ...props }) => <strong {...props} />,
325
- em: ({ node, ref, ...props }) => <em {...props} />,
326
- pre: ({ node, ref, ...props }) => <pre {...props} />,
327
- h1: ({ node, ref, ...props }) => <h1 {...props} />,
328
- h2: ({ node, ref, ...props }) => <h2 {...props} />,
329
- h3: ({ node, ref, ...props }) => <h3 {...props} />,
330
- li: ({ node, ref, ...props }) => <li {...props} />,
331
- ul: ({ node, ref, ...props }) => <ul {...props} />,
332
- ol: ({ node, ref, ...props }) => <ol {...props} />,
333
- blockquote: ({ node, ref, ...props }) => <blockquote {...props} />,
334
- hr: ({ node, ref, ...props }) => <hr {...props} />,
335
- table: ({ node, ref, ...props }) => <div className="overflow-x-auto"><table {...props} /></div>,
336
- th: ({ node, ref, ...props }) => <th {...props} />,
337
- td: ({ node, ref, ...props }) => <td {...props} />,
338
264
  }}
339
265
  >
340
266
  {content as string}
341
- </Markdown>
267
+ </MarkdownRenderer>
342
268
  </div>
343
269
  );
344
270
  };
345
271
 
346
272
  const messageContent = getMessageContent();
347
273
 
274
+ // Resolve artifacts from tool details (e.g. execute_shell.outputFiles)
275
+ const [artifactLinks, setArtifactLinks] = useState<
276
+ { displayName: string; artifactPath: string; url: string; isImage: boolean }[]
277
+ >([]);
278
+
279
+ useEffect(() => {
280
+ const loadArtifacts = async () => {
281
+ const runId = (message as any).workflow_run_id as string | undefined;
282
+ const details = message.details as any;
283
+ const outputFiles: unknown = details && details.outputFiles;
284
+
285
+ if (!runId || !Array.isArray(outputFiles) || outputFiles.length === 0) {
286
+ setArtifactLinks([]);
287
+ return;
288
+ }
289
+
290
+ try {
291
+ const entries = await Promise.all(
292
+ outputFiles.map(async (name: unknown) => {
293
+ if (typeof name !== "string" || !name.trim()) return null;
294
+ const trimmed = name.trim();
295
+ // execute_shell returns relative paths like "result.csv" or "plots/chart.png"
296
+ // canonical artifact name is under out/
297
+ const artifactPath =
298
+ trimmed.startsWith("out/") || trimmed.startsWith("files/") || trimmed.startsWith("scripts/")
299
+ ? trimmed
300
+ : `out/${trimmed}`;
301
+
302
+ const ext = artifactPath.split(".").pop()?.toLowerCase() || "";
303
+ const imageExtensions = new Set(["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg"]);
304
+ const isImage = imageExtensions.has(ext);
305
+
306
+ try {
307
+ const disposition = isImage ? "inline" : "attachment";
308
+ const { url } = await client.files.getArtifactDownloadUrl(runId, artifactPath, disposition);
309
+ return {
310
+ displayName: trimmed,
311
+ artifactPath,
312
+ url,
313
+ isImage,
314
+ };
315
+ } catch (err) {
316
+ console.error(`Failed to resolve artifact URL for ${artifactPath}`, err);
317
+ return null;
318
+ }
319
+ }),
320
+ );
321
+
322
+ setArtifactLinks(
323
+ entries.filter(
324
+ (e): e is { displayName: string; artifactPath: string; url: string; isImage: boolean } => !!e,
325
+ ),
326
+ );
327
+ } catch (error) {
328
+ console.error("Error loading artifact URLs from message details", error);
329
+ setArtifactLinks([]);
330
+ }
331
+ };
332
+
333
+ loadArtifacts();
334
+ }, [message.details, message.timestamp, client]);
335
+
348
336
  // Process content with image URL resolution when component mounts or message changes
349
337
  useEffect(() => {
350
338
  const processContent = async () => {
@@ -507,7 +495,7 @@ export default function MessageItem({ message, showPulsatingCircle = false }: Me
507
495
  )}
508
496
  </div>
509
497
 
510
- <div className="flex items-center gap-2">
498
+ <div className="flex items-center gap-2 print:hidden">
511
499
  <span className="text-xs text-muted">
512
500
  {dayjs(message.timestamp).format("HH:mm:ss")}
513
501
  </span>
@@ -537,9 +525,56 @@ export default function MessageItem({ message, showPulsatingCircle = false }: Me
537
525
  </div>
538
526
  )}
539
527
 
528
+ {/* Auto-surfaced artifacts from tool details (e.g. execute_shell.outputFiles) */}
529
+ {artifactLinks.length > 0 && (
530
+ <div className="mt-3 text-xs">
531
+ <div className="font-medium text-muted mb-1">Artifacts</div>
532
+
533
+ {/* Inline previews for image artifacts */}
534
+ {artifactLinks.some(a => a.isImage) && (
535
+ <div className="mb-2 flex flex-wrap gap-3">
536
+ {artifactLinks
537
+ .filter(a => a.isImage)
538
+ .map(({ displayName, artifactPath, url }) => (
539
+ <div
540
+ key={`${artifactPath}-preview`}
541
+ className="max-w-xs cursor-pointer"
542
+ onClick={() => window.open(url, "_blank")}
543
+ >
544
+ <img
545
+ src={url}
546
+ alt={displayName}
547
+ className="max-w-full h-auto rounded-lg shadow-sm hover:shadow-md transition-shadow"
548
+ />
549
+ <div className="mt-1 text-[11px] text-muted truncate">
550
+ {displayName}
551
+ </div>
552
+ </div>
553
+ ))}
554
+ </div>
555
+ )}
556
+
557
+ {/* Buttons for all artifacts (files and images) */}
558
+ <div className="flex flex-wrap gap-2 print:hidden">
559
+ {artifactLinks.map(({ displayName, artifactPath, url }) => (
560
+ <Button
561
+ key={artifactPath + url}
562
+ variant="outline"
563
+ size="xs"
564
+ className="px-2 py-1 text-xs"
565
+ onClick={() => window.open(url, "_blank")}
566
+ title={artifactPath}
567
+ >
568
+ {displayName}
569
+ </Button>
570
+ ))}
571
+ </div>
572
+ </div>
573
+ )}
574
+
540
575
  {/* Optional details section */}
541
576
  {message.details && (
542
- <div className="mt-2">
577
+ <div className="mt-2 print:hidden">
543
578
  <button
544
579
  onClick={() => setShowDetails(!showDetails)}
545
580
  className="text-xs text-muted flex items-center"
@@ -2,3 +2,4 @@ export * from "./JumpingDots";
2
2
  export { ModernAgentConversation } from "./ModernAgentConversation";
3
3
  export * from "./WaitingMessages";
4
4
  export * from "./AnimatedThinkingDots";
5
+ export { AgentChart, type AgentChartSpec } from "./AgentChart";