@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
@@ -0,0 +1,720 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button, Center, ConfirmModal, errorMessage, Modal, ResizableHandle, ResizablePanel, ResizablePanelGroup, Spinner, useToast, VTooltip, } from '@vertesia/ui/core';
3
+ import { useUITranslation } from '@vertesia/ui/i18n';
4
+ import { useUserSession } from '@vertesia/ui/session';
5
+ import { ArtifactEditingSurface, createUnifiedLineDiff, diffTextSegments, isArtifactRefreshEvent, } from '@vertesia/ui/widgets';
6
+ import { Check, FilePenLine, FileText, GitCompareArrows, ListChecks, RefreshCw, RotateCcw, Save, Sparkles, X, } from 'lucide-react';
7
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
8
+ import { ModernAgentConversation, } from '../../../agent/chat/ModernAgentConversation.js';
9
+ import { resolveTypeCached } from '../../types/typeCatalogCache.js';
10
+ import { DocumentEditingConfigurationSelector, getDocumentEditingProjectDefault, } from './DocumentEditingConfigurationSelector.js';
11
+ import { DocumentEditingLockStatus } from './DocumentEditingLockStatus.js';
12
+ import { persistRunLocalArtifactRefs } from './documentArtifactRefs.js';
13
+ import { DOCUMENT_EDITING_EXCLUDED_TOOLS, DOCUMENT_EDITING_INITIAL_SKILLS, DOCUMENT_EDITING_TOOLS, } from './documentEditingAgentConfig.js';
14
+ import { createDirectEditsAppliedPrompt } from './documentEditingPrompts.js';
15
+ import { createDocumentEditingRunIdentity, DOCUMENT_EDITING_DEFAULT_INTERACTION, findDocumentEditingRun, } from './documentEditingRun.js';
16
+ import { resolveDocumentEditingTarget } from './documentEditingTarget.js';
17
+ import { SaveVersionConfirmModal } from './SaveVersionConfirmModal.js';
18
+ function shortenRunId(id) {
19
+ return id.length > 12 ? `${id.slice(0, 4)}…${id.slice(-4)}` : id;
20
+ }
21
+ function getDocumentDraftPath(documentRootId) {
22
+ return `drafts/${documentRootId}.md`;
23
+ }
24
+ function createDocumentEditingPrompt(object, documentId, documentEtag, draftPath, userPrompt) {
25
+ const documentName = object.name || object.content?.name || 'Document';
26
+ return [
27
+ 'You are collaborating with the user on one specific Markdown document in Vertesia.',
28
+ `Canonical document: [${documentName}](store:${documentId})`,
29
+ `Canonical base revision ID: ${documentId}`,
30
+ `Canonical base ETag: ${documentEtag ?? 'unavailable'}`,
31
+ `Working copy artifact: ${draftPath}`,
32
+ '',
33
+ 'The working copy was hydrated and read before your first turn. It is the source of truth for this editing',
34
+ 'session. Apply requested changes only to that artifact using edit_artifact. Preserve all unrelated content',
35
+ 'exactly. User block edits may already be applied to the artifact; acknowledge them and continue from the',
36
+ 'current artifact generation. Attachments may contain review comments to apply in bulk.',
37
+ '',
38
+ 'Do not call update_document, create_document, or write_artifact for this working copy. The user publishes',
39
+ 'the artifact back to the canonical document with the Save to document button, which enforces the base ETag.',
40
+ '',
41
+ 'You may use execute_shell to regenerate charts, diagrams, and other derived assets. Write generated files',
42
+ "under '/home/daytona/out/' so they sync back to the run, then reference them from Markdown with a run-local",
43
+ "link such as 'artifact:out/chart.png'. Saving the document persists and rewrites those links automatically.",
44
+ '',
45
+ 'Images: never inline image data as base64 data URIs — it bloats the document and cannot be reliably edited.',
46
+ "Keep existing image references (e.g. 'artifact:documents/…' URLs) exactly as they are: they point to durable",
47
+ "storage that outlives this session. Files already in this run's artifact space may be referenced with",
48
+ "run-local links like 'artifact:files/photo.png' — publishing copies them into durable storage and rewrites",
49
+ 'the links automatically.',
50
+ '',
51
+ `User request: ${userPrompt}`,
52
+ ].join('\n');
53
+ }
54
+ /** Chat prompt asking the agent to merge external canonical changes into the working copy. */
55
+ export function createDocumentReconcilePrompt(documentRootId, headDocumentId, draftPath) {
56
+ return [
57
+ 'The canonical document was updated outside this session, so publishing the working copy was rejected.',
58
+ `1) Fetch the latest canonical revision ${headDocumentId} with fetch_document into 'drafts/${documentRootId}.theirs.md'.`,
59
+ `2) Compare it with the working copy '${draftPath}' and merge the external changes into the working copy with edit_artifact, preserving this session's edits.`,
60
+ '3) Reply with a short list of what was merged, plus any conflicting passages and how you resolved them, so I can review before saving again.',
61
+ ].join('\n');
62
+ }
63
+ /** Chat prompt asking the agent for a changelog of the working copy vs the session baseline. */
64
+ export function createDocumentChangeSummaryPrompt(documentRootId, originalDocumentId, draftPath) {
65
+ return [
66
+ `Summarize the changes in the working copy '${draftPath}' relative to the original document revision ${originalDocumentId}.`,
67
+ `If you no longer have the original content, fetch it with fetch_document into 'drafts/${documentRootId}.base.md'.`,
68
+ 'Do not modify the working copy.',
69
+ 'Reply with a concise changelog: grouped bullets, most important first, suitable for a revision note.',
70
+ ].join('\n');
71
+ }
72
+ function getErrorStatus(error) {
73
+ if (!error || typeof error !== 'object' || !('status' in error))
74
+ return undefined;
75
+ return typeof error.status === 'number' ? error.status : undefined;
76
+ }
77
+ function DocumentWorkingCopyDiff({ original, workingCopy }) {
78
+ const segments = useMemo(() => diffTextSegments(original, workingCopy), [original, workingCopy]);
79
+ const counts = useMemo(() => ({
80
+ added: segments.reduce((total, segment) => total + (segment.type === 'added' ? segment.text.length : 0), 0),
81
+ removed: segments.reduce((total, segment) => total + (segment.type === 'removed' ? segment.text.length : 0), 0),
82
+ }), [segments]);
83
+ return (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-muted/10", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-end gap-3 border-b border-mixer-muted/20 px-5 py-2 text-xs", children: [_jsxs("span", { className: "text-destructive", children: ["\u2212", counts.removed] }), _jsxs("span", { className: "text-success", children: ["+", counts.added] })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-auto p-5", children: _jsx("pre", { className: "mx-auto max-w-5xl whitespace-pre-wrap break-words rounded-lg border border-mixer-muted/25 bg-background p-5 font-mono text-xs leading-6 shadow-sm", children: segments.map((segment, index) => {
84
+ if (segment.type === 'removed') {
85
+ return (_jsx("del", { className: "bg-mixer-destructive/15 text-destructive line-through decoration-destructive/50", children: segment.text }, index));
86
+ }
87
+ if (segment.type === 'added') {
88
+ return (_jsx("ins", { className: "bg-mixer-success/15 text-success no-underline", children: segment.text }, index));
89
+ }
90
+ return _jsx("span", { children: segment.text }, index);
91
+ }) }) })] }));
92
+ }
93
+ /**
94
+ * Full document editing workspace: working copy surface plus the editing conversation.
95
+ * Standalone so host applications can embed it in their own layout; DocumentEditingPanel
96
+ * wraps it in a full-screen modal for the Studio object page.
97
+ */
98
+ export function DocumentEditingWorkspace({ object, initialContent = '', onDocumentUpdated, onClose, sendMessageRef, model, startImmediately = false, }) {
99
+ const { client, project, store, user } = useUserSession();
100
+ const { t } = useUITranslation();
101
+ const toast = useToast();
102
+ const internalSendMessageRef = useRef(null);
103
+ const messageRef = sendMessageRef ?? internalSendMessageRef;
104
+ const [agentRunId, setAgentRunId] = useState();
105
+ const [isStarting, setIsStarting] = useState(false);
106
+ const [isTerminating, setIsTerminating] = useState(false);
107
+ const [isResolvingRun, setIsResolvingRun] = useState(true);
108
+ const [isResolvingTarget, setIsResolvingTarget] = useState(true);
109
+ const [targetResolutionFailed, setTargetResolutionFailed] = useState(false);
110
+ const [targetResolutionAttempt, setTargetResolutionAttempt] = useState(0);
111
+ const [showNewSessionConfirm, setShowNewSessionConfirm] = useState(false);
112
+ const providedConfigurationKey = JSON.stringify(model
113
+ ? {
114
+ environment: model.env,
115
+ model: model.model,
116
+ model_options: model.options,
117
+ }
118
+ : {});
119
+ const hasProvidedConfiguration = model !== undefined;
120
+ const providedConfiguration = useMemo(() => JSON.parse(providedConfigurationKey), [providedConfigurationKey]);
121
+ const [isLoadingConfiguration, setIsLoadingConfiguration] = useState(!hasProvidedConfiguration);
122
+ const [isSaving, setIsSaving] = useState(false);
123
+ const [showSaveConfirmation, setShowSaveConfirmation] = useState(false);
124
+ const [isSendingChanges, setIsSendingChanges] = useState(false);
125
+ const [isAgentWorking, setIsAgentWorking] = useState(false);
126
+ const [isEditingManuallyUnlocked, setIsEditingManuallyUnlocked] = useState(false);
127
+ const [hasDirectEditorChanges, setHasDirectEditorChanges] = useState(false);
128
+ const [artifactRefresh, setArtifactRefresh] = useState({ key: 0 });
129
+ const [artifactContent, setArtifactContent] = useState(initialContent);
130
+ const [artifactLoaded, setArtifactLoaded] = useState(false);
131
+ const [originalContent, setOriginalContent] = useState(initialContent);
132
+ const [savedContent, setSavedContent] = useState(initialContent);
133
+ const [workspaceView, setWorkspaceView] = useState('document');
134
+ const [saveConflict, setSaveConflict] = useState();
135
+ const [targetDocumentId, setTargetDocumentId] = useState(object.id);
136
+ const [targetEtag, setTargetEtag] = useState(object.content?.etag);
137
+ const [resolvedEditingPolicy, setResolvedEditingPolicy] = useState();
138
+ const [executionConfiguration, setExecutionConfiguration] = useState(providedConfiguration);
139
+ const configurationSourceRef = useRef(hasProvidedConfiguration ? 'host' : 'none');
140
+ const automaticStartKeyRef = useRef(undefined);
141
+ const seenUpdatesRef = useRef(new Set());
142
+ const artifactGenerationRef = useRef(undefined);
143
+ const agentWorkingRef = useRef(false);
144
+ const flushArtifactChangesRef = useRef(null);
145
+ const documentRootId = object.revision?.root || object.id;
146
+ const draftPath = useMemo(() => getDocumentDraftPath(documentRootId), [documentRootId]);
147
+ const startedBy = user?.sub ? `user:${user.sub}` : undefined;
148
+ const editingScopeKey = `${project?.id ?? 'no-project'}:${documentRootId}`;
149
+ const editingPolicyKey = `${editingScopeKey}:${object.type?.id ?? 'no-type'}`;
150
+ const editingInteraction = resolvedEditingPolicy?.key === editingPolicyKey ? resolvedEditingPolicy.interaction : undefined;
151
+ const editingScopeRef = useRef(editingScopeKey);
152
+ const originalDocumentRef = useRef({ editingScopeKey, id: object.id });
153
+ const lookupIdentityRef = useRef({ documentId: object.id, documentRootId });
154
+ const isDirty = artifactLoaded && artifactContent !== savedContent;
155
+ const isEditingLocked = isAgentWorking && !isEditingManuallyUnlocked;
156
+ if (lookupIdentityRef.current.documentRootId !== documentRootId) {
157
+ lookupIdentityRef.current = { documentId: object.id, documentRootId };
158
+ }
159
+ if (originalDocumentRef.current.editingScopeKey !== editingScopeKey) {
160
+ originalDocumentRef.current = { editingScopeKey, id: object.id };
161
+ }
162
+ useEffect(() => {
163
+ if (editingScopeRef.current === editingScopeKey)
164
+ return;
165
+ editingScopeRef.current = editingScopeKey;
166
+ configurationSourceRef.current = hasProvidedConfiguration ? 'host' : 'none';
167
+ setExecutionConfiguration(providedConfiguration);
168
+ setIsLoadingConfiguration(!hasProvidedConfiguration);
169
+ seenUpdatesRef.current.clear();
170
+ setArtifactContent(initialContent);
171
+ setOriginalContent(initialContent);
172
+ setSavedContent(initialContent);
173
+ setArtifactLoaded(false);
174
+ setHasDirectEditorChanges(false);
175
+ setIsAgentWorking(false);
176
+ setIsEditingManuallyUnlocked(false);
177
+ agentWorkingRef.current = false;
178
+ setWorkspaceView('document');
179
+ setTargetDocumentId(object.id);
180
+ setTargetEtag(object.content?.etag);
181
+ }, [
182
+ editingScopeKey,
183
+ hasProvidedConfiguration,
184
+ initialContent,
185
+ object.content?.etag,
186
+ object.id,
187
+ providedConfiguration,
188
+ ]);
189
+ useEffect(() => {
190
+ let cancelled = false;
191
+ const requestScopeKey = editingScopeKey;
192
+ const requestedDocumentId = originalDocumentRef.current.id;
193
+ setIsResolvingTarget(true);
194
+ setTargetResolutionFailed(false);
195
+ // Commit the target id, ETag, and text only after all reads succeed. A failed
196
+ // head lookup must never turn a historical revision into an editable fallback.
197
+ void resolveDocumentEditingTarget(store.objects, requestedDocumentId)
198
+ .then((target) => {
199
+ if (cancelled || originalDocumentRef.current.editingScopeKey !== requestScopeKey)
200
+ return;
201
+ originalDocumentRef.current = { editingScopeKey: requestScopeKey, id: target.id };
202
+ lookupIdentityRef.current = { documentId: target.id, documentRootId };
203
+ setTargetDocumentId(target.id);
204
+ setTargetEtag(target.etag);
205
+ setOriginalContent(target.content);
206
+ setSavedContent(target.content);
207
+ })
208
+ .catch((error) => {
209
+ console.warn('Failed to resolve the document editing target', {
210
+ error,
211
+ attempt: targetResolutionAttempt,
212
+ });
213
+ if (!cancelled && originalDocumentRef.current.editingScopeKey === requestScopeKey) {
214
+ setTargetResolutionFailed(true);
215
+ }
216
+ })
217
+ .finally(() => {
218
+ if (!cancelled && originalDocumentRef.current.editingScopeKey === requestScopeKey) {
219
+ setIsResolvingTarget(false);
220
+ }
221
+ });
222
+ return () => {
223
+ cancelled = true;
224
+ };
225
+ }, [documentRootId, editingScopeKey, store.objects, targetResolutionAttempt]);
226
+ useEffect(() => {
227
+ let cancelled = false;
228
+ const typeId = object.type?.id;
229
+ if (!typeId) {
230
+ setResolvedEditingPolicy({
231
+ key: editingPolicyKey,
232
+ interaction: DOCUMENT_EDITING_DEFAULT_INTERACTION,
233
+ });
234
+ return;
235
+ }
236
+ void resolveTypeCached(client, typeId).then((type) => {
237
+ if (cancelled)
238
+ return;
239
+ setResolvedEditingPolicy({
240
+ key: editingPolicyKey,
241
+ interaction: type?.editing?.interaction?.trim() || DOCUMENT_EDITING_DEFAULT_INTERACTION,
242
+ });
243
+ });
244
+ return () => {
245
+ cancelled = true;
246
+ };
247
+ }, [client, editingPolicyKey, object.type?.id]);
248
+ useEffect(() => {
249
+ if (agentRunId || configurationSourceRef.current === 'run')
250
+ return;
251
+ if (hasProvidedConfiguration) {
252
+ configurationSourceRef.current = 'host';
253
+ setExecutionConfiguration(providedConfiguration);
254
+ setIsLoadingConfiguration(false);
255
+ }
256
+ else if (configurationSourceRef.current === 'host') {
257
+ configurationSourceRef.current = 'none';
258
+ setExecutionConfiguration({});
259
+ }
260
+ }, [agentRunId, hasProvidedConfiguration, providedConfiguration]);
261
+ useEffect(() => {
262
+ if (hasProvidedConfiguration) {
263
+ setIsLoadingConfiguration(false);
264
+ return;
265
+ }
266
+ if (!project) {
267
+ setIsLoadingConfiguration(false);
268
+ return;
269
+ }
270
+ let cancelled = false;
271
+ const requestScopeKey = editingScopeKey;
272
+ setIsLoadingConfiguration(true);
273
+ void client.projects
274
+ .retrieve(project.id)
275
+ .then((fullProject) => {
276
+ if (cancelled ||
277
+ editingScopeRef.current !== requestScopeKey ||
278
+ configurationSourceRef.current !== 'none') {
279
+ return;
280
+ }
281
+ configurationSourceRef.current = 'project';
282
+ setExecutionConfiguration(getDocumentEditingProjectDefault(fullProject));
283
+ })
284
+ .catch((error) => {
285
+ console.warn('Failed to load the default document editing model', error);
286
+ })
287
+ .finally(() => {
288
+ if (!cancelled)
289
+ setIsLoadingConfiguration(false);
290
+ });
291
+ return () => {
292
+ cancelled = true;
293
+ };
294
+ }, [client, editingScopeKey, hasProvidedConfiguration, project]);
295
+ useEffect(() => {
296
+ setAgentRunId(undefined);
297
+ if (!startedBy || !editingInteraction) {
298
+ setIsResolvingRun(false);
299
+ return;
300
+ }
301
+ let cancelled = false;
302
+ setIsResolvingRun(true);
303
+ void findDocumentEditingRun(client.agents, lookupIdentityRef.current.documentId, documentRootId, startedBy, editingInteraction)
304
+ .then((run) => {
305
+ if (cancelled || !run)
306
+ return;
307
+ setAgentRunId(run.id);
308
+ if (run.config?.environment && run.config.model) {
309
+ configurationSourceRef.current = 'run';
310
+ setExecutionConfiguration({
311
+ environment: run.config.environment,
312
+ model: run.config.model,
313
+ model_options: run.config.model_options,
314
+ });
315
+ }
316
+ })
317
+ .catch((error) => {
318
+ console.warn('Failed to look up an existing document editing run', error);
319
+ })
320
+ .finally(() => {
321
+ if (!cancelled)
322
+ setIsResolvingRun(false);
323
+ });
324
+ return () => {
325
+ cancelled = true;
326
+ };
327
+ }, [client, documentRootId, editingInteraction, startedBy]);
328
+ const handleConfigurationChange = useCallback((value) => {
329
+ configurationSourceRef.current = 'user';
330
+ setExecutionConfiguration(value);
331
+ }, []);
332
+ const handleCopyRunId = useCallback(() => {
333
+ if (!agentRunId)
334
+ return;
335
+ navigator.clipboard
336
+ .writeText(agentRunId)
337
+ .then(() => toast({ status: 'success', title: t('agent.runIdCopied'), duration: 2000 }))
338
+ .catch((error) => console.warn('Failed to copy the agent run id', error));
339
+ }, [agentRunId, t, toast]);
340
+ const handleStartNewSession = useCallback(async () => {
341
+ if (!agentRunId || isTerminating)
342
+ return;
343
+ setIsTerminating(true);
344
+ try {
345
+ await client.agents.terminate(agentRunId, 'cancel');
346
+ toast({ status: 'success', title: t('agent.workflowCancelled'), duration: 2000 });
347
+ }
348
+ catch (error) {
349
+ console.warn('Failed to terminate the document editing run', error);
350
+ }
351
+ finally {
352
+ setIsTerminating(false);
353
+ }
354
+ seenUpdatesRef.current.clear();
355
+ setAgentRunId(undefined);
356
+ setArtifactLoaded(false);
357
+ setArtifactContent(savedContent);
358
+ setHasDirectEditorChanges(false);
359
+ agentWorkingRef.current = false;
360
+ setIsAgentWorking(false);
361
+ setIsEditingManuallyUnlocked(false);
362
+ }, [agentRunId, client.agents, isTerminating, savedContent, t, toast]);
363
+ const startWorkflow = useCallback(async (initialMessage, options) => {
364
+ if (!project ||
365
+ !editingInteraction ||
366
+ isResolvingRun ||
367
+ isResolvingTarget ||
368
+ targetResolutionFailed ||
369
+ isStarting ||
370
+ isLoadingConfiguration) {
371
+ return undefined;
372
+ }
373
+ setIsStarting(true);
374
+ try {
375
+ if (!executionConfiguration.environment || !executionConfiguration.model) {
376
+ toast({ status: 'error', title: t('agent.documentEditingDefaultsRequired'), duration: 5000 });
377
+ return undefined;
378
+ }
379
+ const prompt = createDocumentEditingPrompt(object, targetDocumentId, targetEtag, draftPath, initialMessage?.trim() || t('agent.documentEditingInitialRequest'));
380
+ const identity = createDocumentEditingRunIdentity(targetDocumentId, documentRootId);
381
+ const payload = {
382
+ interaction: editingInteraction,
383
+ interactive: true,
384
+ tool_approval_mode: options?.tool_approval_mode,
385
+ tool_names: DOCUMENT_EDITING_TOOLS,
386
+ excluded_tools: DOCUMENT_EDITING_EXCLUDED_TOOLS,
387
+ initial_skills: DOCUMENT_EDITING_INITIAL_SKILLS,
388
+ initial_tool_calls: [
389
+ {
390
+ id: 'hydrate-working-copy',
391
+ tool: 'fetch_document',
392
+ input: { id: targetDocumentId, mode: 'content', output_artifact: { path: draftPath } },
393
+ },
394
+ {
395
+ id: 'read-working-copy',
396
+ tool: 'read_artifact',
397
+ input: { path: draftPath },
398
+ },
399
+ ],
400
+ data: { user_prompt: prompt },
401
+ config: {
402
+ environment: executionConfiguration.environment,
403
+ model: executionConfiguration.model,
404
+ model_options: executionConfiguration.model_options,
405
+ },
406
+ started_by: startedBy,
407
+ tags: identity.tags,
408
+ properties: identity.properties,
409
+ };
410
+ const run = await client.agents.start(payload);
411
+ setAgentRunId(run.id);
412
+ return { agent_run_id: run.id };
413
+ }
414
+ catch (error) {
415
+ console.error('Failed to start document editing agent', error);
416
+ toast({
417
+ status: 'error',
418
+ title: t('agent.documentEditingStartFailed'),
419
+ description: error instanceof Error ? error.message : undefined,
420
+ duration: 5000,
421
+ });
422
+ return undefined;
423
+ }
424
+ finally {
425
+ setIsStarting(false);
426
+ }
427
+ }, [
428
+ client.agents,
429
+ documentRootId,
430
+ draftPath,
431
+ executionConfiguration,
432
+ editingInteraction,
433
+ isLoadingConfiguration,
434
+ isResolvingRun,
435
+ isResolvingTarget,
436
+ isStarting,
437
+ object,
438
+ project,
439
+ startedBy,
440
+ t,
441
+ targetDocumentId,
442
+ targetEtag,
443
+ targetResolutionFailed,
444
+ toast,
445
+ ]);
446
+ const handleArtifactContentChange = useCallback((content, generation) => {
447
+ artifactGenerationRef.current = generation;
448
+ setArtifactContent(content);
449
+ setArtifactLoaded(true);
450
+ }, []);
451
+ useEffect(() => {
452
+ if (!startImmediately ||
453
+ agentRunId ||
454
+ !project ||
455
+ !editingInteraction ||
456
+ isResolvingRun ||
457
+ isResolvingTarget ||
458
+ targetResolutionFailed ||
459
+ isStarting ||
460
+ isLoadingConfiguration ||
461
+ !executionConfiguration.environment ||
462
+ !executionConfiguration.model) {
463
+ return;
464
+ }
465
+ const automaticStartKey = JSON.stringify({
466
+ scope: editingScopeKey,
467
+ interaction: editingInteraction,
468
+ document: targetDocumentId,
469
+ configuration: executionConfiguration,
470
+ });
471
+ if (automaticStartKeyRef.current === automaticStartKey)
472
+ return;
473
+ automaticStartKeyRef.current = automaticStartKey;
474
+ void startWorkflow(t('agent.documentEditingStartRequest'), { tool_approval_mode: 'full_control' });
475
+ }, [
476
+ agentRunId,
477
+ editingInteraction,
478
+ editingScopeKey,
479
+ executionConfiguration,
480
+ isLoadingConfiguration,
481
+ isResolvingRun,
482
+ isResolvingTarget,
483
+ isStarting,
484
+ project,
485
+ startImmediately,
486
+ startWorkflow,
487
+ t,
488
+ targetDocumentId,
489
+ targetResolutionFailed,
490
+ ]);
491
+ const handleAgentWorkingChange = useCallback((isWorking) => {
492
+ const wasWorking = agentWorkingRef.current;
493
+ agentWorkingRef.current = isWorking;
494
+ setIsAgentWorking(isWorking);
495
+ if (!isWorking) {
496
+ setIsEditingManuallyUnlocked(false);
497
+ if (wasWorking) {
498
+ setArtifactRefresh((current) => ({ key: current.key + 1 }));
499
+ }
500
+ }
501
+ }, []);
502
+ const sendEditingMessage = useCallback((message, inputMetadata) => {
503
+ const sendMessage = messageRef.current;
504
+ if (!sendMessage) {
505
+ toast({ status: 'warning', title: t('agent.artifactEditingUnavailable'), duration: 3000 });
506
+ return;
507
+ }
508
+ sendMessage(message, inputMetadata);
509
+ }, [messageRef, t, toast]);
510
+ const handleArtifactAction = useCallback((action) => {
511
+ const blockType = action.anchor.block_type.replaceAll('_', ' ');
512
+ const displayMessage = action.comment?.trim() || t('agent.editedSelectionMessage', { blockType });
513
+ sendEditingMessage(displayMessage, { editing_action: action });
514
+ }, [sendEditingMessage, t]);
515
+ const handleSave = useCallback(async (createVersion, versionLabel) => {
516
+ if (!artifactLoaded ||
517
+ !targetEtag ||
518
+ !isDirty ||
519
+ isEditingLocked ||
520
+ isSaving ||
521
+ isResolvingTarget ||
522
+ targetResolutionFailed) {
523
+ return;
524
+ }
525
+ setIsSaving(true);
526
+ try {
527
+ // Persist run-local artifact references (session-generated charts, files)
528
+ // into durable documents/ storage and rewrite the links before publishing —
529
+ // the same pass create_document applies. Run artifact storage does not
530
+ // outlive the session, so the canonical document must never depend on it.
531
+ let contentToSave = artifactContent;
532
+ if (agentRunId) {
533
+ const persistence = await persistRunLocalArtifactRefs(client.files, contentToSave, agentRunId, crypto.randomUUID());
534
+ contentToSave = persistence.content;
535
+ }
536
+ const contentType = object.content?.type || 'text/markdown';
537
+ const fileName = object.content?.name || 'content.md';
538
+ const file = new File([new Blob([contentToSave], { type: contentType })], fileName, {
539
+ type: contentType,
540
+ });
541
+ const response = await store.objects.update(targetDocumentId, { content: file }, { createRevision: createVersion, revisionLabel: versionLabel, ifMatch: targetEtag });
542
+ setTargetDocumentId(response.id);
543
+ setTargetEtag(response.content?.etag);
544
+ setSavedContent(contentToSave);
545
+ setSaveConflict(undefined);
546
+ setShowSaveConfirmation(false);
547
+ onDocumentUpdated?.(response.id, createVersion);
548
+ toast({ status: 'success', title: t('store.textSaved'), duration: 2500 });
549
+ // Sync the rewritten links back into the working copy so it matches the
550
+ // published revision. A concurrent agent edit (412) just leaves the copy
551
+ // dirty, which is accurate — it no longer matches what was published.
552
+ if (agentRunId && contentToSave !== artifactContent && artifactGenerationRef.current) {
553
+ try {
554
+ await client.agents.updateArtifactContent(agentRunId, draftPath, {
555
+ content: contentToSave,
556
+ generation: artifactGenerationRef.current,
557
+ });
558
+ setArtifactRefresh((current) => ({ key: current.key + 1 }));
559
+ }
560
+ catch (syncError) {
561
+ console.warn('Failed to sync persisted artifact links into the working copy', syncError);
562
+ }
563
+ }
564
+ }
565
+ catch (error) {
566
+ // Two conflict shapes: an in-place edit of the target revision fails the
567
+ // If-Match precondition (412), while a new external revision moves the head
568
+ // and the save is rejected as not-head (400). Both mean the canonical
569
+ // document changed since this session's baseline.
570
+ const status = getErrorStatus(error);
571
+ let isConflict = status === 412;
572
+ if (status === 412 || status === 400) {
573
+ try {
574
+ const target = await resolveDocumentEditingTarget(store.objects, targetDocumentId);
575
+ if (target.id !== targetDocumentId || status === 412) {
576
+ isConflict = true;
577
+ // Re-point the save target at the new head so the user can choose
578
+ // to overwrite it, and offer an agent-assisted merge instead.
579
+ setTargetDocumentId(target.id);
580
+ setTargetEtag(target.etag);
581
+ setSaveConflict({ headId: target.id });
582
+ }
583
+ }
584
+ catch (resolveError) {
585
+ console.warn('Failed to resolve the new head after a save conflict', resolveError);
586
+ }
587
+ }
588
+ toast({
589
+ status: 'error',
590
+ title: t('store.errorSavingText'),
591
+ description: isConflict
592
+ ? t('store.textConflict')
593
+ : errorMessage(error, t('store.errorSavingTextDefault')),
594
+ duration: 5000,
595
+ });
596
+ }
597
+ finally {
598
+ setIsSaving(false);
599
+ }
600
+ }, [
601
+ agentRunId,
602
+ artifactContent,
603
+ artifactLoaded,
604
+ client.agents,
605
+ client.files,
606
+ draftPath,
607
+ isDirty,
608
+ isEditingLocked,
609
+ isResolvingTarget,
610
+ isSaving,
611
+ object.content?.name,
612
+ object.content?.type,
613
+ onDocumentUpdated,
614
+ store.objects,
615
+ t,
616
+ targetDocumentId,
617
+ targetEtag,
618
+ targetResolutionFailed,
619
+ toast,
620
+ ]);
621
+ const handleReconcile = useCallback(() => {
622
+ const sendMessage = messageRef.current;
623
+ if (!sendMessage || !saveConflict) {
624
+ toast({ status: 'warning', title: t('agent.artifactEditingUnavailable'), duration: 3000 });
625
+ return;
626
+ }
627
+ sendMessage(createDocumentReconcilePrompt(documentRootId, saveConflict.headId, draftPath));
628
+ setSaveConflict(undefined);
629
+ setWorkspaceView('document');
630
+ }, [documentRootId, draftPath, messageRef, saveConflict, t, toast]);
631
+ const handleSummarizeChanges = useCallback(() => {
632
+ const sendMessage = messageRef.current;
633
+ if (!sendMessage) {
634
+ toast({ status: 'warning', title: t('agent.artifactEditingUnavailable'), duration: 3000 });
635
+ return;
636
+ }
637
+ sendMessage(createDocumentChangeSummaryPrompt(documentRootId, originalDocumentRef.current.id, draftPath));
638
+ }, [documentRootId, draftPath, messageRef, t, toast]);
639
+ const flushFullEditorChanges = useCallback(async () => {
640
+ if (workspaceView !== 'editor' || !hasDirectEditorChanges)
641
+ return true;
642
+ return Boolean(await flushArtifactChangesRef.current?.());
643
+ }, [hasDirectEditorChanges, workspaceView]);
644
+ const handleWorkspaceViewChange = useCallback(async (nextView) => {
645
+ if (nextView === workspaceView)
646
+ return;
647
+ if (!(await flushFullEditorChanges()))
648
+ return;
649
+ setWorkspaceView(nextView);
650
+ }, [flushFullEditorChanges, workspaceView]);
651
+ const handleCloseWorkspace = useCallback(async () => {
652
+ if (!(await flushFullEditorChanges()))
653
+ return;
654
+ onClose?.();
655
+ }, [flushFullEditorChanges, onClose]);
656
+ const handleSendChangesToAgent = useCallback(async () => {
657
+ const sendMessage = messageRef.current;
658
+ if (!sendMessage || !agentRunId || isEditingLocked || isSendingChanges) {
659
+ toast({ status: 'warning', title: t('agent.artifactEditingUnavailable'), duration: 3000 });
660
+ return;
661
+ }
662
+ setIsSendingChanges(true);
663
+ try {
664
+ const flushed = await flushArtifactChangesRef.current?.();
665
+ if (!flushed)
666
+ return;
667
+ // Hand the agent the exact persisted delta so it can update its context
668
+ // without spending another turn reading or re-applying the artifact.
669
+ const unifiedDiff = createUnifiedLineDiff(flushed.previous, flushed.current, { context: 1 });
670
+ if (unifiedDiff)
671
+ sendMessage(createDirectEditsAppliedPrompt(draftPath, unifiedDiff));
672
+ setHasDirectEditorChanges(false);
673
+ toast({ status: 'success', title: t('agent.changesSentToAgent'), duration: 2000 });
674
+ }
675
+ finally {
676
+ setIsSendingChanges(false);
677
+ }
678
+ }, [agentRunId, draftPath, isEditingLocked, isSendingChanges, messageRef, t, toast]);
679
+ return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [_jsxs("div", { className: "flex h-14 shrink-0 items-center justify-between gap-3 border-b border-mixer-muted/20 px-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-semibold", children: object.name || object.content?.name }), _jsxs("div", { className: "flex items-center gap-2 text-xs text-muted", children: [_jsxs("span", { className: "flex shrink-0 items-center gap-1.5", children: [isDirty ? (_jsx("span", { "aria-hidden": true, className: "size-1.5 rounded-full bg-attention" })) : artifactLoaded ? (_jsx(Check, { className: "size-3 text-success" })) : null, isDirty ? t('store.unsavedChanges') : t('store.textSaved')] }), _jsx("span", { "aria-hidden": true, className: "text-mixer-muted/60", children: "\u00B7" }), _jsx(VTooltip, { description: `${t('agent.workingCopy')}: ${draftPath}`, asChild: true, children: _jsxs("span", { className: "min-w-0 truncate font-mono", children: ["drafts/", shortenRunId(documentRootId), ".md"] }) }), _jsx("span", { "aria-hidden": true, className: "text-mixer-muted/60", children: "\u00B7" }), _jsx(VTooltip, { description: `${t('agent.originalDocument')}: ${originalDocumentRef.current.id}`, asChild: true, children: _jsxs("span", { className: "shrink-0 font-mono", children: [t('agent.originalDocument').toLowerCase(), ' ', shortenRunId(originalDocumentRef.current.id)] }) })] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsxs("div", { className: "flex items-center rounded-md border border-mixer-muted/25 bg-muted/10 p-0.5", children: [_jsxs(Button, { variant: workspaceView === 'document' ? 'secondary' : 'ghost', size: "sm", className: "h-7 gap-1.5", onClick: () => void handleWorkspaceViewChange('document'), children: [_jsx(FileText, { className: "size-3.5" }), t('agent.document')] }), _jsxs(Button, { variant: workspaceView === 'editor' ? 'secondary' : 'ghost', size: "sm", className: "h-7 gap-1.5", onClick: () => void handleWorkspaceViewChange('editor'), children: [_jsx(FilePenLine, { className: "size-3.5" }), t('agent.fullEditor')] }), _jsxs(Button, { variant: workspaceView === 'diff' ? 'secondary' : 'ghost', size: "sm", className: "h-7 gap-1.5", onClick: () => void handleWorkspaceViewChange('diff'), disabled: !artifactLoaded || artifactContent === originalContent, children: [_jsx(GitCompareArrows, { className: "size-3.5" }), t('agent.reviewChanges')] })] }), workspaceView === 'diff' ? (_jsxs(Button, { variant: "ghost", size: "sm", className: "h-8 gap-1.5", onClick: handleSummarizeChanges, disabled: !artifactLoaded || artifactContent === originalContent, children: [_jsx(ListChecks, { className: "size-3.5" }), t('agent.summarizeChanges')] })) : null, _jsx(VTooltip, { description: t('agent.refresh'), asChild: true, children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setArtifactRefresh((current) => ({ key: current.key + 1 })), disabled: !agentRunId, "aria-label": t('agent.refresh'), children: _jsx(RefreshCw, { className: "size-4" }) }) }), _jsx("div", { "aria-hidden": true, className: "mx-1 h-6 w-px bg-mixer-muted/25" }), _jsx(DocumentEditingConfigurationSelector, { value: executionConfiguration, onChange: handleConfigurationChange, disabled: Boolean(agentRunId) || isStarting || isResolvingRun, isLoading: isLoadingConfiguration }), !agentRunId ? (_jsxs(Button, { variant: "primary", size: "sm", className: "h-8 gap-1.5", onClick: () => void startWorkflow(t('agent.documentEditingStartRequest')), disabled: isStarting ||
680
+ isResolvingRun ||
681
+ isResolvingTarget ||
682
+ isLoadingConfiguration ||
683
+ targetResolutionFailed ||
684
+ !project ||
685
+ !editingInteraction ||
686
+ !executionConfiguration.environment ||
687
+ !executionConfiguration.model, children: [isStarting ? _jsx(Spinner, { size: "sm" }) : _jsx(Sparkles, { className: "size-4" }), isStarting ? t('agent.startingAgent') : t('agent.documentEditingStart')] })) : null, agentRunId ? (_jsxs(_Fragment, { children: [_jsx(VTooltip, { description: agentRunId, asChild: true, children: _jsx(Button, { variant: "ghost", size: "sm", className: "font-mono text-[11px] text-muted", onClick: handleCopyRunId, "aria-label": t('agent.copyRunId'), children: shortenRunId(agentRunId) }) }), _jsx(VTooltip, { description: t('agent.startNewConversation'), asChild: true, children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => {
688
+ if (isDirty) {
689
+ setShowNewSessionConfirm(true);
690
+ }
691
+ else {
692
+ void handleStartNewSession();
693
+ }
694
+ }, disabled: isTerminating, "aria-label": t('agent.startNewConversation'), children: _jsx(RotateCcw, { className: "size-4" }) }) })] })) : null, _jsx("div", { "aria-hidden": true, className: "mx-1 h-6 w-px bg-mixer-muted/25" }), _jsxs(Button, { variant: "primary", className: "min-w-36 gap-2", onClick: () => setShowSaveConfirmation(true), disabled: !isDirty ||
695
+ !targetEtag ||
696
+ isEditingLocked ||
697
+ isSaving ||
698
+ isResolvingTarget ||
699
+ targetResolutionFailed, children: [isSaving ? _jsx(Spinner, { size: "sm" }) : _jsx(Save, { className: "size-4" }), t('agent.saveToDocument')] }), onClose ? (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => void handleCloseWorkspace(), "aria-label": t('agent.close'), children: _jsx(X, { className: "size-4" }) })) : null] })] }), saveConflict ? (_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-mixer-attention/30 bg-mixer-attention/10 px-4 py-2 text-sm", children: [_jsx("span", { className: "min-w-0 truncate text-attention", children: t('agent.saveConflictNotice') }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: handleReconcile, children: t('agent.askAgentToReconcile') }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setSaveConflict(undefined), "aria-label": t('agent.close'), children: _jsx(X, { className: "size-4" }) })] })] })) : null, _jsxs(ResizablePanelGroup, { direction: "horizontal", className: "min-h-0 flex-1", children: [_jsx(ResizablePanel, { defaultSize: 65, minSize: 35, className: "min-w-0 bg-background", children: _jsx("div", { className: "flex h-full min-h-0 flex-col", children: _jsx("div", { className: "min-h-0 flex-1", children: workspaceView === 'diff' ? (_jsx(DocumentWorkingCopyDiff, { original: originalContent, workingCopy: artifactContent })) : (_jsx(ArtifactEditingSurface, { runId: agentRunId, path: draftPath, viewMode: workspaceView === 'editor' ? 'document' : 'components', baselineContent: originalContent, initialContent: savedContent, refreshKey: artifactRefresh.key, refreshDetails: artifactRefresh.details, readOnly: isEditingLocked, allowComments: Boolean(agentRunId), onContentChange: handleArtifactContentChange, onAction: handleArtifactAction, onSendMessage: sendEditingMessage, onSendChangesToAgent: handleSendChangesToAgent, hasUnsentChanges: isDirty && hasDirectEditorChanges, isSendingChanges: isSendingChanges, sendChangesDisabled: !agentRunId || isEditingLocked, toolbarStatus: isAgentWorking ? (_jsx(DocumentEditingLockStatus, { isLocked: isEditingLocked, onToggleLock: () => setIsEditingManuallyUnlocked((isUnlocked) => !isUnlocked) })) : undefined, onDocumentEdit: () => setHasDirectEditorChanges(true), flushChangesRef: flushArtifactChangesRef })) }) }) }), _jsx(ResizableHandle, { withHandle: true }), _jsx(ResizablePanel, { defaultSize: 35, minSize: 25, className: "min-w-[320px]", children: isResolvingRun || isResolvingTarget ? (_jsx(Center, { className: "h-full", children: _jsx(Spinner, { size: "lg" }) })) : targetResolutionFailed ? (_jsxs(Center, { className: "h-full flex-col gap-3 px-6 text-center", children: [_jsx("div", { className: "text-sm text-muted", children: t('agent.failedToLoadDocument') }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => setTargetResolutionAttempt((attempt) => attempt + 1), children: t('agent.retry') })] })) : (_jsx(ModernAgentConversation, { agentRunId: agentRunId, startWorkflow: startWorkflow, resetWorkflow: () => setAgentRunId(undefined), onRestart: (run) => setAgentRunId(run.id), sendMessageRef: messageRef, onMessage: (message) => {
700
+ const details = message.details;
701
+ if (!isArtifactRefreshEvent(details, draftPath))
702
+ return;
703
+ const updateKey = `${message.timestamp}:${details?.path}:${details?.generation ?? ''}`;
704
+ if (seenUpdatesRef.current.has(updateKey))
705
+ return;
706
+ seenUpdatesRef.current.add(updateKey);
707
+ setArtifactRefresh((current) => ({
708
+ key: current.key + 1,
709
+ details,
710
+ }));
711
+ }, onAgentWorkingChange: handleAgentWorkingChange, title: t('agent.documentEditing'), initialMessage: t('agent.documentEditingWelcome'), startButtonText: isStarting ? t('agent.startingAgent') : t('agent.startAgent'), placeholder: t('agent.documentEditingPlaceholder'), initialToolApprovalMode: "full_control", hideObjectLinking: true, hideHeader: true, showRightPanel: false, fullWidth: true, interactive: true })) })] }), _jsx(ConfirmModal, { isOpen: showNewSessionConfirm, title: t('agent.newSessionDiscardTitle'), content: t('agent.newSessionDiscardDescription'), onConfirm: () => {
712
+ setShowNewSessionConfirm(false);
713
+ void handleStartNewSession();
714
+ }, onCancel: () => setShowNewSessionConfirm(false) }), _jsx(SaveVersionConfirmModal, { isOpen: showSaveConfirmation, onClose: () => setShowSaveConfirmation(false), onConfirm: handleSave, isLoading: isSaving })] }));
715
+ }
716
+ export function DocumentEditingPanel({ object, initialContent, onClose, onDocumentUpdated, sendMessageRef, model, startImmediately, }) {
717
+ const { t } = useUITranslation();
718
+ return (_jsx(Modal, { isOpen: true, onClose: onClose, size: "full", noCloseButton: true, disableCloseOnClickOutside: true, className: "gap-0 overflow-hidden p-0", description: t('agent.documentEditingWelcome'), children: _jsx(DocumentEditingWorkspace, { object: object, initialContent: initialContent, onClose: onClose, onDocumentUpdated: onDocumentUpdated, sendMessageRef: sendMessageRef, model: model, startImmediately: startImmediately }) }));
719
+ }
720
+ //# sourceMappingURL=DocumentEditingPanel.js.map